AcWing 221. 龙哥的问题
题意
给一个整数 n ( 1 ≤ n ≤ 2 31 ) n(1\le n \le 2^{31}) n(1≤n≤231) ,求 ∑ i = 1 n g c d ( i , n ) \sum_{i=1}^n gcd(i,n) ∑i=1ngcd(i,n)
解法
枚举
n
n
n 的因子。
a
n
s
=
∑
i
=
1
n
g
c
d
(
i
,
n
)
=
∑
d
d
∑
i
=
1
n
[
g
c
d
(
i
,
n
)
=
=
d
]
=
∑
d
d
∑
i
=
1
n
[
g
c
d
(
i
/
d
,
n
/
d
)
=
=
1
]
=
∑
d
d
∑
i
=
1
n
/
d
[
g
c
d
(
i
,
n
/
d
)
=
=
1
]
=
∑
d
d
⋅
φ
(
n
/
d
)
\begin{aligned} ans&=\sum_{i=1}^n gcd(i,n)\\ &=\sum_d d \sum_{i=1}^n[gcd(i,n)==d]\\ &=\sum_d d\sum_{i=1}^n [gcd(i/d,n/d)==1]\\ &=\sum_d d\sum_{i=1}^{n/d}[gcd(i,n/d)==1]\\ &=\sum_d d\cdot \varphi (n/d) \end{aligned}
ans=i=1∑ngcd(i,n)=d∑di=1∑n[gcd(i,n)==d]=d∑di=1∑n[gcd(i/d,n/d)==1]=d∑di=1∑n/d[gcd(i,n/d)==1]=d∑d⋅φ(n/d)
线性枚举
n
n
n 的因子,然后计算欧拉函数累加答案。
1
⋅
1
0
9
1\cdot 10^9
1⋅109 范围的数最多因子个数大约是一千多,所以复杂度为
O
(
1000
n
)
O(1000\sqrt n)
O(1000n)
代码
#pragma region
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define tr t[root]
#define lson t[root << 1]
#define rson t[root << 1 | 1]
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
#pragma endregion
const int maxn = 1e7 + 5;
int euler_phi(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;
scanf("%d", &n);
ll ans = 0;
ll i;
for (i = 1; i * i < n; ++i) {
if (n % i == 0) ans += 1LL * i * euler_phi(n / i) + 1LL * n / i * euler_phi(i);
}
if (1LL * i * i == n) ans += 1LL * i * euler_phi(i);
printf("%lld\n", ans);
}