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 }

相关推荐