GCD nyoj 1007 (欧拉函数+欧几里得)
GCD nyoj 1007 (欧拉函数+欧几里得)
GCD
时间限制:1000 ms | 内存限制:65535 KB
难度:3
- 描述
- The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written (a,b),is the largest divisor common to a and b,For example,(1,2)=1,(12,18)=6.
(a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem:
Given integers N and M,please answer sum of X satisfies 1<=X<=N and (X,N)>=M.
- 输入
- The first line of input is an integer T(T<=100) representing the number of test cases. The following T lines each contains two numbers N and M (1<=N<=10^9, 1<=M<=10^9), representing a test case.
- 输出
- Output the answer mod 1000000007
- 样例输入
-
3 1 1 10 2 10000 72
- 样例输出
-
1 35 1305000
题意:1<= x <= n ,求gcd(x,n) >= m 说有满足条件的x的和 (最后要模Mod=1000000007)
分析:如果是求满足条件的x的个数:
因为x要满足1<=x<=n 且gcd(x,n)>=m,所以x为n的因子,即gcd(x,n)=x>=m,设y=n/x,
则y的欧拉函数为小于y且与y互质的数的个数。假设与y互质的数为p1,p2,p3……,那么gcd(x*pi,n)=x>=m.
即要找出所有符合要求的y的欧拉函数值的和即可。
因为1<= x <= n 若gcd(x,n) = x >= m 推出x是n的因子 y = n/x 与y互质且小于y的数pi 总共有eular(y)个
gcd(x*pi,n) = x >= m 所以此时满足条件的x的个数有eular(y)个又因为 gcd(a,n) = gcd(n-a,n) 【定理记住】 所以此条件下x的和sum = n*eular(y)/2
最后再依此求出n的所有因子 计算sum相加即可
计算x的总和:附上代码/* author:谦智 HDU 2588-GCD(欧拉函数) 数论 */ #include<iostream> using namespace std; const int Mod = 1000000007; #define LL long long LL eular(LL n) ; LL eularSum(LL k) { if (k == 1) return 1;//特殊值 return k*eular(k)/2; } int main() { int t; cin >> t; while (t--) { LL n, m; cin >> n >> m; LL sum = 0; if (n == 1 && m == 1) {//特殊情况 cout << 1 << endl; continue; } for (LL i = 1; i*i <= n; i++) { if (n%i == 0) { if (i >= m) { sum = (sum + n*eular(n/i)/2)%Mod; //==》 sum = (sum + i*(n/i)*eular(n/i)/2)%Mod // sum = (sum + i*eularSum(n/i))%Mod;//总共有 eular(n/i)个x使得gcd(x,n) >= m } if (n/i >= m && i*i != n) { //只需要在这里加一个i== 1的情况上面不要加 不然会重复 if (i == 1) sum = (sum + n)%Mod;//当eular(i) < 2时只需要加上此时唯一满足条件的x即可 其他的eular(i)一定都是偶数因为gcd(a,n)= gcd(n-a,n) else sum = (sum + n*eular(i)/2)%Mod; // sum = (sum + n/i*eularSum(i))%Mod; } } } cout << sum << endl; } } LL eular(LL n) { LL ans = n; for (LL i = 2; i*i <= n; i++) { if (n%i == 0) { ans = ans/i*(i-1); while (n%i == 0) { n /= i; } } } if (n != 1) ans = ans/n*(n-1); return ans; }
计算x的个数:附上代码
//计算 x小于n 且gcd(x,n) >= m 的x的个数 #include<iostream> using namespace std; int eular(int n) ; int main() { int t; cin >> t; while (t--) { int n, m; cin >> n >> m; int sum = 0; for (int i = 1; i*i <= n; i++) { if (n%i == 0) { if (i >= m) { sum += eular(n/i); } else if (n/i >= m && i*i != n) { sum += eular(i); } } } cout << sum << endl; } } int eular(int n) { int ans = n; for (int i = 2; i*i <= n; i++) { if (n%i == 0) { ans = ans/i*(i-1); } while (n%i == 0) { n /= i; } } if (n != 1) ans = ans/n*(n-1); return ans; }