题目
枚举gcd,最后化简得
∑
i
=
1
n
3
φ
(
x
)
∑
i
=
1
⌊
n
x
⌋
[
x
∣
⌊
x
i
3
⌋
]
\sum^{\sqrt[3]{n}}_{i=1}φ(x)\sum^{\lfloor \frac n x\rfloor}_{i=1}[x|\lfloor\sqrt[3]{xi}\rfloor]
i=1∑3nφ(x)i=1∑⌊xn⌋[x∣⌊3xi⌋]
后面那个式子通过考虑x的倍数来解决,即枚举x,2x,3x,…,考虑此时i如何取值,因此可以发现每次i是连续的一段一段取得,区间类似于
[
p
3
x
2
,
(
p
x
+
1
)
3
−
1
x
]
[p^3x^2,\frac {(px+1)^3-1} x]
[p3x2,x(px+1)3−1]
最后可以得到,后面那个sigma就是
(
⌊
n
x
⌋
−
q
3
x
2
+
1
)
+
(
3
x
⋅
(
2
p
+
1
)
(
p
+
1
)
p
6
+
3
⋅
(
p
+
1
)
p
2
+
p
)
(\lfloor \frac n x\rfloor-q^3x^2+1)+(3x·\frac {(2p+1)(p+1)p}{6}+3·\frac {(p+1)p}{2}+p)
(⌊xn⌋−q3x2+1)+(3x⋅6(2p+1)(p+1)p+3⋅2(p+1)p+p)
其中p是满足
(
p
x
+
1
)
3
−
1
x
≤
⌊
n
x
⌋
\frac {(px+1)^3-1} x\le\lfloor\frac n x\rfloor
x(px+1)3−1≤⌊xn⌋的最大值
q是满足
q
3
x
2
≤
⌊
n
x
⌋
q^3x^2\le\lfloor\frac n x\rfloor
q3x2≤⌊xn⌋的最大值
且当
p
=
q
p=q
p=q时,不计算上面q那部分括号里的值
然后直接做是
O
(
T
n
3
)
O(T\sqrt[3]n)
O(T3n)的,理论(题解上说)可以过,但实际TLE
通过(打表)分析得到p是连续一段,且q只会出现在区间边界处(1个或0个),所以可以分块计算,预处理
φ
(
x
)
φ(x)
φ(x)和
x
⋅
φ
(
x
)
x·φ(x)
x⋅φ(x)的前缀和,同时用二分计算三次根号,可以在
O
(
n
3
+
T
n
6
log
n
)
O(\sqrt[3]n+T\sqrt[6]n\log n)
O(3n+T6nlogn)时间内得到答案
最后答案要取模,但全程答案不会超过int128,所以只在最后取模即可
代码:
#include<cstdio>
#include<iostream>
#define LL __int128
#define M 10000005
#define mo 998244353
using namespace std;
//所有用LL定义的类型全改成int128(long long类型不用改,只改宏定义的)
int prime[M/10],phi[M],sum_phi[M],x_phi[M];
bool vis[M];
LL n;
LL gao(LL id)
{
return id*(id+1)*(2*id+1)/6;
}
LL pt(LL x)
{
return x*x*x;
}
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;
}
LL sear(LL x,LL cao)
{
LL l=1,r=x,mid;
if (r>cao) r=cao;
while (l<=r)
{
mid=l+r>>1;
if (mid<=x/mid/mid) l=mid+1;
else r=mid-1;
}
return l-1;
}
main()
{
phi[1]=1;
for (int i=2;i<=M-5;++i)
{
if (!vis[i])
phi[i]=i-1,
prime[++prime[0]]=i;
for (int j=1;j<=prime[0]&&prime[j]*i<=M-5;++j)
{
vis[prime[j]*i]=1;
if (i%prime[j])
phi[i*prime[j]]=phi[i]*(prime[j]-1);
else
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
}
}
for (int i=1;i<=M-5;++i)
sum_phi[i]=(sum_phi[i-1]+phi[i])%mo,
x_phi[i]=(x_phi[i-1]+1LL*i*phi[i]%mo)%mo;
int T;
for (scanf("%d",&T);T;--T)
{
read(n);//改成__int128读入
LL idd,tmp,last;
int lim=1;
LL ans=0;
lim=sear(n,10000000);
idd=lim;
for (int x=1;x<=lim;x=last+1)
{
tmp=(n/x/x/x);
idd=sear(tmp,idd);
last=sear(n/idd/idd/idd,10000000);
if (last!=x) ans+=3*gao(idd)*(x_phi[last-1]-x_phi[x-1])+(3*(idd+1)*idd/2+idd)*(sum_phi[last-1]-sum_phi[x-1]);
if (pt(idd*last+1)-1>n/last*last)
ans+=(3*gao(idd-1)*last+3*(idd-1)*idd/2+idd+(n/last)-idd*idd*idd*last*last)*phi[last];
else
ans+=(3*gao(idd)*last+3*(idd+1)*idd/2+idd)*phi[last];
}
printf("%d\n",(int)(ans%998244353));
}
}