题解 P1390 【公约数的和】
莫比乌斯反演入门题
前置芝士
- 数论分块,一点点莫比乌斯反演
正文
可以考虑先求
然后再去重。
可以想到枚举
化简式子
因为
所以现在转化为了
由
所以原式转化为
转化一下求和顺序
后面两个即为求
所以答案转化为
后面那玩意用数论分块和前缀和即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define int long long
inline int read(){
register int x=0,f=0,ch=getchar();
while('0'>ch||ch>'9')f^=ch=='-',ch=getchar();
while('0'<=ch&&ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
return f?-x:x;
}
const int MAX=2000005;
int n,tot,p[MAX],f[MAX],mu[MAX];
inline void Gmu(){
mu[1]=1;tot=0;
for(register int i=2;i<=n;++i){
if(!f[i]){
p[++tot]=i;
mu[i]=-1;
}
for(register int j=1;j<=tot&&i*p[j]<=n;++j){
f[i*p[j]]=1;
if(i%p[j]==0){
mu[i*p[j]]=0;
break;
}
mu[i*p[j]]=-mu[i];
}
}
for(register int i=1;i<=n;++i)mu[i]+=mu[i-1];
}
int res,ans;
inline void solve(int n,int p){
res=0;
for(register int l=1,r;l<=n;l=r+1){
r=n/(n/l);
res+=(mu[r]-mu[l-1])*(n/l)*(n/l);
}
ans+=res*p;
}
signed main(){
n=read();
Gmu();
for(register int p=1;p<=n;++p)solve(n/p,p);
printf("%lld\n",(ans-(n*(n+1)>>1))>>1);
return 0;
}
写得有什么问题麻烦私信笔者,谢谢