求 ∑ni=1∑d|igcd(d,id)
题目相当于求
很像一道经典莫比乌斯反演题了。
设f(k)表示gcd(i,j)=k的对数,设g(k)表示k|gcd(i,j)的对数。
于是有
所以问题变成了求
我们发现g并不能O(1)得出,然后就连O(n)都做不到了,但是别急。
我们设T=i*k,然后交换主体,于是原式就等于
显然当T> n√ 时g的值都为0所以T只需要枚举到 n√ 。
我们发现后面的部分只跟T有关系,所以可以预处理出来,用a(T)表示
然后,我们得到了一个十分优美的式子
现在问题的关键变成怎样求g了。
所以我们可以分块O( nk−−√ )计算g(k),于是总复杂度就是O( ∑n√k=1nk−−√ )=O( n34 )(由于本人太弱,也不知道这个怎么算出来的)。
同时我们发现 [ni∗k2] 很快就会返回0。
于是当它为0时,就可以退出计算当前的g(k),这样就可以跑得挺快了。
该题有很多解法,本人比较蠢,只会莫比乌斯反演,出题人的方法简洁高效,
然而我没听懂(我太弱鸡了)。
#include
#include
#include
#define ll long long
using namespace std;
const int maxn=316227;
ll a[maxn+5],mu[maxn+5],c[maxn+5];
bool bz[maxn+5];
int main()
{
ll n,m,ans=0;
scanf("%lld",&n);
m=sqrt(n);
mu[1]=1;
for (int i=2;i<=m;i++){
if (!bz[i]){
mu[i]=-1;
c[++c[0]]=i;
}
for (int j=1;j<=c[0];j++){
if (i*c[j]>m) break;
bz[i*c[j]]=1;
if (i%c[j]==0){
mu[i*c[j]]=0;
break;
}
mu[i*c[j]]=-mu[i];
}
}
for (int i=1;i<=m;i++) if (mu[i]!=0){
for (int j=1;i*j<=m;j++) a[i*j]+=mu[i]*j;
}
for (int k=1;k<=m;k++){
ll m1=n/k,l=1,r=0,x=0,m2=m1/k,s=0;
while (l<=m1){
x=m2/l;
if (x==0) break;
r=m2/x;
s+=(r-l+1)*x;
l=r+1;
}
ans+=s*a[k];
}
printf("%lld\n",ans);
}