SDOI2012 longge的问题

题目描述 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 }

 

posted @ 2015-04-02 18:24  Xstsow  阅读(233)  评论(0编辑  收藏  举报