1. 程式人生 > >bzoj 2818 GCD 數論 歐拉函數

bzoj 2818 GCD 數論 歐拉函數

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

4

Sample Output

4

HINT

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 數論 歐拉函數