您的位置:首页 > 其它

SDOI2012 longge的问题

2015-04-02 18:24 190 查看
题目描述 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所有的因数就可以了。

#include<iostream>
#include<vector>
#include<cmath>
#include<cstring>
using namespace std;

vector<long long> ys;

long long n, ans;

long long phi(long long n) {      //欧拉函数
if (n == 1) return 1;
long long k = n;
for (int i = 2; i*i <= n; i++)
if (n % i == 0)
{
k /= i;
while (n % i == 0) n /= i;
k *= i-1;
}
if (n > 1) {
k /= n;
k *= (n - 1);
}
return k;
}

int main() {
cin >> n;
int nn = floor(sqrt(n));  //上界
for (int i = 1; i <= nn; i++)   //找因数
if (n % i == 0)
if (i*i == n) ys.push_back(i);
else {
ys.push_back(i);
ys.push_back(n/i);
}
for (int i = 0; i < ys.size(); i++) {
ans += ys[i] * phi(n / ys[i]);
}
cout << ans << "\n";
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: