Problem
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} floor} [gcd(i,lfloor frac{n}{d} floor) = 1] ][= sum_{d=1}^n d*φ(lfloor frac{n}{d} floor) ][= 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
",ans);
return 0;
}
Summary
这个定理很重要!!!