题目描述
Description
Longge 的数学成绩非常好,并且他非常乐于挑战高难度的数学问题。现在问题来了:
定一个整数 N ,你需要求出 Σ gcd(i, N)(1<=i<=N) 。
输入描述
Input Description
的第一行包含一个整数 N ,如题所示
输出描述
Output Description
第一行包含一个整数,为所求的答案。
样例输入
Sample Input
6
样例输出
Sample Output
15
数据范围及提示
Data Size & Hint
对于 60% 的数据, 0<N<=2^16 。
对于 100% 的数据, 0<N<=2^32 。
我们设GCD(i,n)=k的i的个数为A(K)个,这样答案就等于 K1*(A(K1)) + K2 * (A(K2)) +...+ KP*(A(KP)),其中,K1 K2 ...KP分别为n的约数。
1-n的范围内可以被k整除的数一共有 n/k 个,在这n/k个数字中,有的数字GCD(i,n)=k,而有些GCD(i,n) = ck(c>1,c∈R)。那么我们需要找出那些数字 GCD(i,n)=k。
首先,数字k一定满足GCD(k,n)=k,如果想让k乘以一个数后依旧能满足GCD(k,n)=k的话,那么他所乘的这个数必须小于并互质与n/k的,小于很好理解。我需要解释的就是为什么需要互质,取出一个n/k的因数(不包括1),得到数字pk,n必然可以整除pk,这样GCD(pk,n)也就等于 k*p了。
求小于并互质的数,我们可以用欧拉函数。
所以,我们只需要找出n所有的因数就可以了。
1 #include<iostream> 2 #include<vector> 3 #include<cmath> 4 #include<cstring> 5 using namespace std; 6 7 vector<long long> ys; 8 9 long long n, ans; 10 11 12 long long phi(long long n) { //欧拉函数 13 if (n == 1) return 1; 14 long long k = n; 15 for (int i = 2; i*i <= n; i++) 16 if (n % i == 0) 17 { 18 k /= i; 19 while (n % i == 0) n /= i; 20 k *= i-1; 21 } 22 if (n > 1) { 23 k /= n; 24 k *= (n - 1); 25 } 26 return k; 27 } 28 29 int main() { 30 cin >> n; 31 int nn = floor(sqrt(n)); //上界 32 for (int i = 1; i <= nn; i++) //找因数 33 if (n % i == 0) 34 if (i*i == n) ys.push_back(i); 35 else { 36 ys.push_back(i); 37 ys.push_back(n/i); 38 } 39 for (int i = 0; i < ys.size(); i++) { 40 ans += ys[i] * phi(n / ys[i]); 41 } 42 cout << ans << "\n"; 43 return 0; 44 }