HDU - 2588 GCD (欧拉函数)

这题实际上就是一个求欧拉函数的题目,我们知道欧拉函数是表示:小于等于正整数N,且与N互质的正整数的个数,记为phi(N)。关于欧拉函数具体可以看看这篇bolg:https://www.cnblogs.com/DynastySun/p/9364673.html

题目中给出N和M要求满足GCD(X, N) >= M, (1 <= X <= N)的X的个数,一看数据范围 1000000000 大概能猜出应该是 O(√N) 或者O(logN)复杂度左右能过。但仔细一想发现与O(logN)似乎关系不大,O(√N)更好想一些。这与欧拉函数有什么关系呢?我们知道我们可以利用欧拉函数求出 GCD(X ,N) == 1 的X的个数,然后我们怎么求GCD(X ,N) == 2的X的个数呢?我们间接求,我们可以求出GCD(X, N/2) == 1的个数,这就是GCD(X, N) == 2 的X的个数,其中的道理不难明白。以此类推 GCD(X, N) == K 可以由 GCD(X, N/K) == 1求出。现在我们可以考虑O(√N)的算法了,题目要求GCD(X, N) >= M的X的个数,我们就可以先求出GCD(X, N) < M的X的个数,再用N减去即可。现在我们就可以枚举GCD(X, N)的各种情况,先从GCD(X, N) == 1开始枚举一直gcd=2, gcd=3, gcd=4......往下枚举,这里有个技巧,我们在枚举GCD(X, N) = K的时候可以顺便枚举出GCD(X, N) == N/K,所以我们只需要枚举到 √N 即可。详细的部分可以见代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cmath>
 6 using namespace std;
 7 
 8 typedef long long LL;
 9 typedef unsigned long long ULL;
10 
11 //求欧拉函数
12 int phi(int n){
13     int m = (int)sqrt(n+0.5);
14     int ans = n;
15     for(int i = 2; i <= m; ++i) if(n%i == 0){
16         while(n%i == 0)
17             n /= i;
18         ans = ans/i*(i-1);
19     }
20     if(n > 1) ans = ans/n*(n-1);
21     return ans;
22 }
23 
24 int main(){
25     int T;
26     scanf("%d", &T);
27     while(T--){
28         int M, N, t, ans;
29         scanf("%d%d", &N, &M);
30         t = (int)sqrt(N+0.5);   //避免浮点误差
31         ans = N;
32         for(int i = 1; i <= t; ++i) if(N%i == 0){
33             int a = N/i;
34             if(i < M) ans -= phi(a);
35             //当n是平方数的时候, i == a 。我们为了防止重复减,加上一个 a != i的条件
36             if(a != i && a < M) ans -= phi(i);
37         }
38         printf("%d\n", ans);
39     }
40     return 0;
41 }
View Code

 

posted @ 2018-08-05 21:08  DyastySun  阅读(171)  评论(0编辑  收藏  举报