题目描述: 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对.
思路:莫比乌斯反演的套路题,先设f(n)表示为gcd(i,j)=n的对数,g(n)表示为n | gcd(i,j)的对数,则g(n) = ∑n|df(d)=n/d*n/d
则f(d) = ∑t=1g(t*d)*mu(t) (mu代表莫比乌斯函数,1<=t<=n/d), 然后只要枚举小于等于n的素数就行了
#include<iostream> #include<algorithm> #include<string.h> #include<string> #include<vector> #include<cstdio> #include<queue> #include<map> #include<set> #include<math.h> using namespace std; const int inf=0x3f3f3f3f; const int maxn=1e7+5; typedef long long ll; int dir[4][2]={-1,0,1,0,0,-1,0,1}; int mu[maxn]; int sum[maxn]; int prime[maxn]; int tot; int vis[maxn]; void table(){ memset(mu,0,sizeof(mu)); memset(sum,0,sizeof(sum)); memset(vis,0,sizeof(vis)); tot=0; mu[1]=1; sum[1]=1; for(int i=2;i<maxn;i++){ if(!vis[i]) { prime[tot++]=i; mu[i]=-1; } sum[i]=sum[i-1]+mu[i]; for(int j=0;j<tot&&prime[j]*i<maxn;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0) break; else mu[i*prime[j]]=-mu[i]; } } } int main(){ ll n; ios::sync_with_stdio(false); table(); while(cin>>n){ ll res=0; for(ll i=0;i<tot&&prime[i]<=n;i++){ ll k=prime[i]; ll m=n/k; ll ans=0; for(ll x=1,y;x<=m;){ y=m/(m/x); ans+=(m/x)*(m/x)*(sum[y]-sum[x-1]); x=y+1; } res+=ans; } cout<<res<<endl; } }