这题实际上就是一个求欧拉函数的题目,我们知道欧拉函数是表示:小于等于正整数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 ", ans); 39 } 40 return 0; 41 }