[算进] POJ 2480(欧拉函数)

Problem

ACwing 题目地址

POJ 题目地址

Solution

定理

\[\sum_{i=1}^n gcd(i,n) = \sum_{d|n} d*φ(\frac{n}{d})\]

证明:
\[\sum_{i=1}^n gcd(i,n)\]
\[= \sum_{d=1}^n \sum_{i=1}^n \ [gcd(i,n) = d] * d\]
\[= \sum_{d=1}^n d*\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \ [gcd(i,\lfloor \frac{n}{d} \rfloor) = 1]\]
\[= \sum_{d=1}^n d*φ(\lfloor \frac{n}{d} \rfloor)\]
\[= \sum_{d|n} d*φ(\frac{n}{d})\]
证毕。

同样还有个小发现,右边这个式子是单位函数和欧拉函数的狄里克雷卷积,即 \(id*φ\)

有了这个式子,我们就直接 \(\sqrt{n}\) 枚举约数,然后分解质因数算欧拉函数。这样算的复杂度上限好像是 \(O(n)\) ?因为求欧拉函数分解质因数这里跑不满,所以是可以过的。

Code

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline 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<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
int n,ans;
int Phi(int n) {
    if(n == 1) return 1;
    int res = 1;
    for(int i=2;i<=sqrt(n);++i) {
        if(n % i == 0) {
            res *= (i-1); n /= i;
            while(n % i == 0) {
                res *= i; n /= i;
            }
        }
    }
    if(n > 1) res *= (n-1);
    return res;
}
signed main()
{
    n = read();
    int S = sqrt(n);
    for(int i=1;i<=S;++i) {
        if(n % i == 0) {
            ans += i * Phi(n/i);
            if(i*i != n) {
                ans += (n/i) * Phi(i);
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

Summary

这个定理很重要!!!

猜你喜欢

转载自www.cnblogs.com/BaseAI/p/12292624.html