bzoj 2818 GCD 数论 欧拉函数
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 }