BZOJ 2705: [SDOI2012]Longge的問題(euler函數)

2705: [SDOI2012]Longge的問題

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 1638  Solved: 1030
[Submit][Status][Discuss]

Description

Longge的數學成績非常好,並且他非常樂於挑戰高難度的數學問題。現在問題來了:給定一個整數N,你需要求出∑gcd(i, N)(1<=i <=N)。

Input

一個整數,爲N。

Output

一個整數,爲所求的答案。

Sample Input

6

Sample Output

15

HINT

【數據範圍】

對於60%的數據,0<N<=2^16。

對於100%的數據,0<N<=2^32。



題目中要求出∑gcd(i,N)(1<=i<=N)。

枚舉n的約數k,令s(k)爲滿足gcd(m,n)=k,(1<=m<=n)m的個數,則ans=sigma(k*s(k)) (k爲n的約數)

因爲gcd(m,n)=k,所以gcd(m/k,n/k)=1,於是s(k)=euler(n/k)

phi可以在根號的時間內求出


#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#define LL long long 
using namespace std;
const int MAXN = 1000000 + 10;
int read()
{
    int x = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f *= -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
int euler(int n)
{
    int m = (int) sqrt(n + 0.5);
    int ans = n;
    for(int i=2;i<=m;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;
}
int main()
{
    int n; n = read();
    long long ans = 0;
    for(int i=1;i*i<=n;i++)
    {
        if(n % i == 0)
        {
            ans += i * euler(n / i);
            if(n / i != i)
                ans += (n / i) * euler(i);
        }
    }
    printf("%lld\n", ans);
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章