欧拉函数——HYSBZ - 2818

题目链接

计算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\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/helman/p/11354161.html