[俺们学校的题]伪.GCD

GCD

题面:

  给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对.

思路:

  首先两个数gcd(x,y)=p为质数,那么令x=k1*p,y=k2*p,由于是最大公因数,所以有k1k2互质,那么根据每一个p我们可以构造出一些不同的k1k2(k1,k2<=n/p),于是求k1,k2可行组合就变成了求 1~n/p范围之内的互质组数。我们运用欧拉筛同时解决找p和互质组数的问题

  首先解决互质组数的问题。我们设f[i]为1~i中的互质二元组个数。则有递推式:

  f[i]=f[i-1]+2*φ(i)

  因为1~i-1我们已经计算过了,所以考虑当前的i与1~i之间组成的互质二元组个数。很显然的,个数为φ(i).欧拉筛求解。由于二元组无序,所以*2

  在欧拉筛的时候,可以同时求出质数p和φ(i).所以求出答案。

  注意在欧拉筛是从2开始,所以初始化f[1]=1;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<fstream>
using namespace std;
#define ll long long
ll phi[10000001],prm[10000001],n,cnt,f[10000001];
bool vis[10000001];
inline void findphi(){
    phi[1]=1,prm[1]=0;
    for (ll i=2;i<=n;++i)
    {
        if (!vis[i]) { prm[++cnt]=i, phi[i]=i-1; }
        for (ll j=1;j<=cnt && i*prm[j]<=n;++j)
        {
            vis[i*prm[j]]=1;
            if (i%prm[j]==0) { phi[i*prm[j]]=phi[i]*prm[j]; break; }
            if (i%prm[j]!=0) phi[i*prm[j]]=phi[i]*(prm[j]-1);   
        }
        f[i]=f[i-1]+2*phi[i];
    }
    return; 
}
int main(){
    cin>>n;
    cnt=0;
    f[1]=1;
    findphi();
    ll ans=0;
    for(int i=1;i<=cnt;++i){
        ans+=f[n/prm[i]];
    }
    cout<<ans;    
}
posted @ 2019-12-21 17:26  clockwhite  阅读(219)  评论(0编辑  收藏  举报