PDFios
输入格式:c++
输出格式:函数
输入样例#1:spa
10
100
200000
0code
输出样例#1:blog
67
13015
143295493160ci
这道题我用莫比乌斯反演和欧拉函数都写了一遍,发现欧拉函数比莫比乌斯反演优秀?rem
求全部\(gcd=k\)的数对的个数,记做\(f[k],ans=\sum_{i=1}^{n}(f[i]-1)\),为何还要-1,咱们注意到\(j=i+1\),本身与本身是不算的,再乘上这个数的大小\(k\)就能够了get
咱们发现要求\(\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}{gcd(i,j)}\),咱们令\(gcd(i,j)=k\),则必有\(gcd(a\times k,b\times k)=k\to gcd(a,b)=1\),咱们枚举这两个数中大的那个,另外一个数就有\(phi[i](1<=i <=n/k)\)个,因此\(f[n]=\sum_{i=1}^{n/k}\phi(i)\)it
筛一下欧拉函数求前缀和就能够了
那么?莫比乌斯反演怎么写呢?
\(ans=\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}gcd(i,j)\)
\(ans=\sum_{i=1}^{n}\sum_{j=1}^{n}gcd(i,j)\)
我么观察这两个式子的区别,一个是从j从1开始,另外一个是从i+1开始,这两个式子是具备几何意义的,上面的式子求得是一个三角形的答案(且不包括对角线),下面的是矩形.那么咱们用下面的式子-对角线上的答案再除以2就是上面的答案了
(对角线上的答案就是\(gcd(i,i)=i\),因此一个等比数列求和就行了)
下面的式子很好反演,套路套路....
\[\sum_{d=1}^{n}d\sum_{i=1}^{n}\sum_{j=1}^{n}[gcd(i,j)==d]\]
\[\sum_{d=1}^{n}d\sum_{p=1,p|i,p|j}^{\lfloor\frac{n}{d}\rfloor}\mu(p) \lfloor\frac{n}{d\times p}\rfloor\lfloor\frac{n}{d\times p}\rfloor\]
线性筛莫比乌斯函数,而后套个整除分块就行了(仍是没有第一种方法快,若是莫比乌斯反演有比博主还快的方法,请告知我)
#include<bits/stdc++.h> #define lol long long #define il inline #define rg register #define Min(a,b) (a)<(b)?(a):(b) #define Max(a,b) (a)>(b)?(a):(b) #define NN 4000000 using namespace std; const int N=4e6+10; int n,tot; lol phi[N],prime[N]; bool vis[N]; il void init() { phi[1]=1; for(rg int i=2;i<=NN;i++) { if(!vis[i]) prime[++tot]=i,phi[i]=i-1; for(rg int j=1;j<=tot && i*prime[j]<=NN;j++) { vis[i*prime[j]]=1; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; } else phi[i*prime[j]]=phi[i]*(prime[j]-1); } } for(rg int i=1;i<=NN;i++) phi[i]+=phi[i-1]; } int main() { ios::sync_with_stdio(0); init(); while(cin>>n) { lol ans=0; if(n==0) break; for(rg int i=1;i<=n;i++) ans+=1ll*(phi[n/i]-1)*i; cout<<ans<<endl; } }
#include<bits/stdc++.h> #define in(i) (i=read()) #define il extern inline #define rg register #define mid ((l+r)>>1) #define ll(x) (x<<1) #define rr(x) (x<<1|1) #define Min(a,b) ((a)<(b)?(a):(b)) #define Max(a,b) ((a)>(b)?(a):(b)) #define lol __int128 using namespace std; const lol N=4e6+10; lol read() { lol ans=0, f=1; char i=getchar(); while (i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();} while (i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48), i=getchar(); return ans*f; } lol cnt; lol vis[N]={0,1},prime[N],mu[N]={0,1}; void init() { for (lol i=2;i<=N-10;i++) { if(!vis[i]) prime[++cnt]=i,mu[i]=-1; for (lol j=1;j<=cnt && prime[j]*i<=N-10;j++) { vis[i*prime[j]]=1; if(i%prime[j]==0) break; mu[i*prime[j]]=-mu[i]; } }for (lol i=1;i<=N-10;i++) mu[i]+=mu[i-1]; } lol work(lol d,lol n,lol ans=0) { n/=d; for (lol l=1,r;l<=n;l=r+1) { r=n/(n/l); ans+=(mu[r]-mu[l-1])*(n/l)*(n/l); }return ans; } int main() { long long ans,n; init(); while(scanf("%lld",&n)==1 && n) { ans=0; for (lol i=1;i<=n;i++) ans+=i*work(i,n); printf("%lld\n",(ans-(n+1)*n/2)/2); } return 0; }