计算gcd(x,y)为素数的(x,y)有多少对
首先有一个必要的式子,gcd(x,y)=素数p => gcd(x/p,y/p)=1
所以若y>x,在确定y的情况下,所有满足与y/p互质的数的个数,即y/p的欧拉函数值
所以我们可以先筛一遍欧拉函数,并求前缀和,方便之后使用
这样sum[n/p]=phi[1]+phi[2]+...+phi[y/p]+...+phi[n/p]
代表你已经求了让y>x时,gcd=p的所有对数
然后还有x>y的情况,就sum[n/p]*2
然后还要注意一下phi[1]这个东西
它表示gcd(p,p)=p,虽然你求phi[p]的时候不会算上它,但是你求的是phi[p/p]
这里的phi[1]是默认为1的,说明你每个素数都多算了一次
题目代码
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; typedef long long LL; const int maxn=1e7+7; int phi[maxn],prime[maxn]; LL sum[maxn]; bool check[maxn]; int cnt=0; void euler(){ phi[1]=1; sum[0]=0; sum[1]=1; for(int i=2;i<maxn;i++){ if(!check[i]){ prime[cnt++]=i; phi[i]=i-1; } for(int j=0;j<cnt&&i*prime[j]<maxn;j++){ check[i*prime[j]]=true; if(i%prime[j]) phi[i*prime[j]]=phi[i]*(prime[j]-1); else { phi[i*prime[j]]=phi[i]*prime[j]; break; } } sum[i]=sum[i-1]+phi[i]; } } LL n; int main(){ euler(); scanf("%lld",&n); LL ans=0; for(int i=0;i<cnt&&prime[i]<=n;i++){ ans+=2*sum[n/prime[i]]; ans--; } printf("%lld ",ans); return 0; }