题意
求
\[
\sum_{i=1}^ngcd(\lfloor\sqrt[3]i\rfloor, i)
\]
\(n \leq 10^{21}\)
解
官方题解讲的大部分都很明白了,主要是有两个地方有点莫名其妙,想了整整七天才想明白。。。是我太菜了
记\(m=\lfloor\sqrt[3]n\rfloor\)
原式
\(=\sum_{a=1}^{m-1}\sum_{i=a^3}^{(a+1)^3-1}gcd(a,i)+\sum_{i=m^3}^ngcd(m,i)\)
设\(f(a, n)=\sum_{i=1}^ngcd(a,i)\)
则\(f(a,n)=\sum_{d|a}d\sum_{i=1}^{\frac{n}{d}}[gcd(\frac{a}{d},i)==1]=\sum_{d|a}d\sum_{e|\frac{a}{d}}\mu(e)\lfloor\frac{n}{de}\rfloor\)
这个是反演演出来的。。。理解成容斥也可以。。。
然后第一个摸不着头脑的地方是下一步。。。下一步最关键的是要去设\(T=de\),观察到上式枚举的\(d,e\)是\(a\)的两个“不相交”的因子(意会一下XD)
所以\(T|a,d|T\),因此实际上可以变换成
\(f(a,n)=\sum_{T|a}\sum_{d|T}d\mu(\frac{T}{d})\lfloor\frac{n}{T}\rfloor=\sum_{T|a}\lfloor\frac{n}{T}\rfloor\sum_{d|T}d\mu(\frac{T}{d})\)
后面那个是个公式,等于\(\varphi(T)\),所以\(f(a,n) = \sum_{T|a}\lfloor\frac{n}{T}\rfloor\varphi(T)\)
这个\(O(\sqrt n)\)搞定
接下来是答案的前半部分,代入\(f(a,(a+1)^3-1)-f(a,a^3-1)\)得
\(\sum_{a=1}^{m-1}\sum_{T|a}\varphi(T)(\lfloor\frac{(a+1)^3-1}{T}\rfloor-\lfloor\frac{a^3-1}{T}\rfloor)\)
下一步设\(a=bT\),交换两个求和符号也有点摸不着头脑。。。意思就是从先枚举\(a\)改为先枚举\(T\)小于等于\(m-1\)再枚举小于等于\(m-1\)的\(T\)的倍数\(a\),也就相当于枚举\(b\)从1到\(\lfloor\frac{m-1}{T}\rfloor\).
然后那一通拆括号变形计算就略了,设\(y = \lfloor\frac{m-1}{T}\rfloor\)最后答案是
\[
\sum_{T=1}^{m-1}\varphi(T)[3T\sum_{b=1}^yb^2+3\sum_{b=1}^yb+\sum_{b=1}^y1]
\]
里面的三个都直接套公式求和就搞定了。。
我写的太丑了,全改成int128会T...还要注意一下能用ll就别用int128
#include <bits/stdc++.h>
#define LL long long
#define MAXN 10000000
using namespace std;
const LL mod = 998244353;
const LL inv6 = 166374059, inv2 = 499122177;
LL gcd(LL a, LL b)
{
return b?gcd(b, a%b):a;
}
int prime[MAXN + 8];
int phi[MAXN + 8];
bool notprime[MAXN + 8];
int ind = 0;
void getprime()
{
notprime[1] = true;
phi[1] = 1;
for (int i = 2; i <= MAXN; ++i)
{
if (!notprime[i])
{
prime[++ind] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= ind && i * prime[j] <= MAXN; ++j)
{
notprime[i * prime[j]] = true;
if (i % prime[j] == 0)
{
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
__int128_t n;
LL tripleroot(__int128_t n)
{
__int128_t l = 1, r = 100000000;
while (l < r)
{
__int128_t mid = (l + r) / 2;
if (mid * mid * mid < n)
l = mid + 1;
else
r = mid;
}
return (LL)(l - (l * l * l > n));
}
LL f(LL a, __int128_t n)
{
LL ret = 0;
for (LL T = 1; T * T <= a; ++T)
{
if (a % T) continue;
ret = (ret + (n / T) * phi[T] % mod) % mod;
if (T * T != a)
{
LL B = a / T;
ret = (ret + (n / B) * phi[B] % mod) % mod;
}
}
return ret;
}
template <class T>
void read(T &x) {
static char ch;static bool neg;
for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar());
for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar());
x=neg?-x:x;
}
int main()
{
getprime();
int __;
read(__);
while (__--)
{
read(n);
if (n <= 7)
{
LL ret = 0;
for (LL i = 1; i <= n; ++i)
ret += gcd(1, i);
cout << ret << endl;
continue;
}
LL m = tripleroot(n);
LL ans = (f(m, n) - f(m, (__int128_t)m * m * m - 1) + mod) % mod;
for (LL T = 1; T <= m - 1; ++T)
{
LL y = (m - 1) / T;
ans = (ans + phi[T] * (((3 * T % mod * y % mod * (y + 1) % mod * (2 * y + 1) % mod * inv6 % mod)
+ (3 * y % mod * (y + 1) % mod * inv2 % mod)
+ y) % mod) % mod) % mod;
}
cout << ans << endl;
}
}