BZOJ 2818 GCD 【欧拉函数 || 莫比乌斯反演】
传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2818
2818: Gcd
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 9236 Solved: 4126
[Submit][Status][Discuss]
Description
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.
Input
一个整数N
Output
如题
Sample Input
4
Sample Output
4
HINT
对于样例(2,2),(2,4),(3,3),(4,2)
1<=N<=10^7
解题思路:
老套路:GCD( x, y ) = p 转换成 GCD( x/p, y/p ) = 1;
那么按照原来的配方,我们需要枚举 x/p 或者 y/p 其中一个数,然后另外一个数的总数通过欧拉函数求得。
假设选择枚举 y/p ,那么还需要暴力一遍枚举素数。(一开始就是直接暴力。。。)
然而O( n ) 内可以同时筛出素数和欧拉函数值:https://oi.abcdabcd987.com/sieve-prime-in-linear-time/
同时记录一下欧拉函数前缀和 sum[k] ,根据上面的转换我们可知:
如果给出 x <= y ,则直接枚举素数枚举y,然后欧拉函数求所有方案数即可;
但是这里没有明确表明 x 和 y 的大小关系, 但是我们还是只求一半 即 (默认 x <= y)的情况,然后这个答案乘以 2 就是 (y <= x)的情况了,需要去一下重(即 x = y = 1)的情况。
枚举 素数 p ,求 [ 1, N/p ] 中互质的数对的总数, 即 2*sum[ N/p ] - 1;
AC code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 const int MAXN = 1e7+10; 5 bool com[MAXN]; 6 int primes, prime[MAXN], phi[MAXN]; 7 LL sum[MAXN]; 8 9 void get_phi(int n){ 10 phi[1] = 1; 11 for (int i = 2; i <= n; ++i) 12 { 13 if (!com[i]) 14 { 15 prime[primes++] = i; 16 phi[i] = i-1; 17 } 18 for (int j = 0; j < primes && i*prime[j] <= n; ++j) 19 { 20 com[i*prime[j]] = true; 21 if (i % prime[j]) 22 phi[i*prime[j]] = phi[i]*(prime[j]-1); 23 else 24 { phi[i*prime[j]] = phi[i]*prime[j]; break; } 25 } 26 //sum[i] = sum[i-1]+phi[i]; 27 } 28 } 29 int main() 30 { 31 int N; 32 scanf("%d", &N); 33 get_phi(N); 34 sum[1] = 1; 35 for(int i = 2; i <= N/2; i++){ 36 sum[i] = sum[i-1]+phi[i]; 37 // phi[i] = phi[i-1]+phi[i]; 38 } 39 // printf("%d\n", phi[1]); 40 LL ans = 0; 41 for(int i = 0; i < primes; i++){ 42 ans = ans + (sum[N/prime[i]]*2-1); 43 } 44 printf("%lld\n", ans); 45 46 return 0; 47 }