感觉这道题很不错,莫比乌斯反演学习的是这篇博客:ACdreamers。
正好是里面的例题可以加深理解。
设
f(d)
为
d=gcd(x,y)
满足的对数。
设
F(d)
为
d|gcd(x,y)
满足的对数。
F(d)=⌊nd⌋∗⌊nd⌋
F(x)=∑x|df(d)
f(x)=∑x|dμ(dx)F(d)
ans=∑p∑p|dμ(dp)F(d)
ans=∑p∑p|dμ(dp)∗⌊nd⌋∗⌊nd⌋
ans=∑d⌊nd⌋∗⌊nd⌋∗∑p|dμ(dp)
预处理出 ∑p|dμ(dp) ,然后 o(n) 复杂度内搞定,如果用分块加速+前缀和,那么复杂度会降到 o(n−−√) 。我上一篇博客有介绍。
设
sum(d)=∑p|dμ(dp)
这里比较特殊的是
p
是质数。在素数筛法中
当
p|d
时:
sum(d∗p)=μ(d)
。
当
p
不能整除
o(n)复杂度算出了 sum(x) 值。
总的复杂度就是 o(n)
代码:
#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y) for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)
using namespace std;
const int maxn = 10000010;
int prime[maxn],mu[maxn],sum[maxn];
bool check[maxn];
void Mobius(){
memset(check,false,sizeof(check));
mu[1] = 1;
prime[0] = 0;
FOR(i,2,maxn){
if(!check[i]){
mu[i] = -1;
sum[i] = 1;
prime[++prime[0]] = i;
}
FOR(j,1,prime[0]+1){
if(i*prime[j] >= maxn) break;
check[i*prime[j]] = true;
if(i % prime[j]){
mu[i*prime[j]] = -mu[i];
sum[i*prime[j]] = mu[i] - sum[i];
}
else{
mu[i*prime[j]] = 0;
sum[i*prime[j]] = mu[i];
break;
}
}
}
}
int n;
void work(){
LL ans = 0;
FOR(i,2,n+1){
ans += (LL)(n/i)*(LL)(n/i)*sum[i];
}
printf("%lld\n",ans);
}
int main()
{
//freopen("test.in","r",stdin);
Mobius();
while(~scanf("%d",&n)){
work();
}
return 0;
}