bzoj 2818 GCD 數論 歐拉函數
阿新 • • 發佈:2017-12-24
sum void using hint con else align 數論 font
bzoj【2818】Gcd
Description
給定整數N,求1<=x,y<=N且Gcd(x,y)為素數的
數對(x,y)有多少對.
Input
一個整數N
Output
如題
Sample Input
4Sample Output
4HINT
hint
對於樣例(2,2),(2,4),(3,3),(4,2)
1<=N<=10^7
題解一(自己yy)
phi[i]表示與x互質的數的個數
即gcd(x,y)=1 1<=y<x
∴對於x,y 若a為素數
則gcd(xa,ya)=a
即滿足xa<=N即可,這個答案即為滿足條件數的個數
n是10e7,可以O(N)先求出phi
一種方法可以N log N即,二分質數使其滿足,但不夠優秀
發現x(枚舉值)不斷增大,即質數個數不斷減少,所以單調性
所以O(N)即可。
題解二
求1<=x,y<=N且Gcd(x,y)為素數的數對(x,y)有多少對
枚舉每個素數,然後每個素數p對於答案的貢獻就是(1 ~ n / p) 中有序互質對的個數
而求1~m中有序互質對x,y的個數,可以令y >= x, 當y = x時,有且只有y = x = 1互質,
當y > x時,確定y以後符合條件的個數x就是 phiy
所以有序互質對的個數為(1 ~ n/p)的歐拉函數之和乘2減1(要求的是有序互質對,乘2以後減去(1, 1)多算的一次)
那麽就只需要先篩出歐拉函數再求個前綴和就可以了
思路二更優秀,hzw大佬。
1 #include<iostream> 2 #include<cstdio> 3 #define ll long long 4 #define N 10000005 5 using namespace std; 6 int n,p,tot; 7 int phi[N],pri[1000005]; 8 bool mark[N]; 9 ll ans,sum[N]; 10 void getphi() 11 { 12 phi[1]=1; 13 for(int i=2;i<=n;i++) 14 { 15 if(!mark[i]){phi[i]=i-1;pri[++tot]=i;} 16 for(int j=1;j<=tot;j++) 17 { 18 int x=pri[j]; 19 if(i*x>n)break; 20 mark[i*x]=1; 21 if(i%x==0){phi[i*x]=phi[i]*x;break;} 22 else phi[i*x]=phi[i]*phi[x]; 23 } 24 } 25 } 26 int main() 27 { 28 scanf("%d",&n); 29 getphi(); 30 for(int i=1;i<=n;i++) 31 sum[i]=sum[i-1]+phi[i]; 32 for(int i=1;i<=tot;i++) 33 ans+=sum[n/pri[i]]*2-1; 34 printf("%lld",ans); 35 return 0; 36 }
bzoj 2818 GCD 數論 歐拉函數