求
∑
(
i
,
n
)
\sum (i,n)
∑(i,n) ,
n
≤
2
32
n\le2^{32}
n≤232 。
所有小于
n
n
n 的数都可以对答案产生贡献,考虑利用
g
c
d
gcd
gcd 缩小数据范围
那么按照
g
c
d
gcd
gcd 分类?
( i , n ) = 1 (i,n)=1 (i,n)=1 的数有 ϕ ( n ) \phi(n) ϕ(n) 个。
(
i
,
n
)
=
k
(i,n)=k
(i,n)=k 的数有几个?显然就是
(
i
/
k
,
n
/
k
)
=
1
(i/k,n/k)=1
(i/k,n/k)=1 的数的个数
ϕ
(
n
/
k
)
\phi(n/k)
ϕ(n/k)
但是只是这样还不够,因为我们要算的是贡献(
所以要求的应该是
k
⋅
ϕ
(
n
/
k
)
k\cdot\phi(n/k)
k⋅ϕ(n/k)
于是只需要求
∑
d
∣
n
(
n
/
d
)
⋅
ϕ
(
d
)
\sum\limits_{d|n}(n/d)\cdot\phi(d)
d∣n∑(n/d)⋅ϕ(d)
把
ϕ
(
d
)
\phi(d)
ϕ(d) 拆开继续化式子还可以进一步降低复杂度。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
unsigned long long n, sq, ans, xsq;
unsigned long long phi(unsigned long long x)
{
unsigned long long ret = x;
xsq = 1ull * sqrt(1.0 * x);
for (unsigned long long i = 2ull; i <= xsq; ++i)
{
if (x % i == 0) ret = ret / i * (i - 1);
while (x % i == 0) x /= i;
}
return (x > 1ull) ? (ret / x * (x - 1ull)) : ret;
}
int main()
{
scanf("%lld", &n);
sq = 1ull * sqrt(1.0 * n);
for (unsigned long long i = 1ull; i <= sq; ++i)
{
if (n % i == 0)
{
ans += (n / i) * phi(i);
if (i * i != n) ans += i * phi(n / i);
}
}
printf("%lld", ans);
return 0;
}