[俺们学校的题]伪.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; }