求 ∑gcd(i,N):答案是积性函数,质因数分解后在每个质因子幂 p^a 上乘局部因子 p^(a-1)·(p+a(p-1)),O(√N) 单次求解。
OJ: roj
题目 ID: 3098
难度:省选/NOI-
标签:数论积性函数质因数分解欧拉函数
创建: 2026-10-01 16:45
更新: 2026-10-07 13:50
形式化题目
给定正整数
正解
思路
1. 按 gcd 取值分组
把
2. 积性 + 局部因子
(展开
于是对
代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-01 17:00
# update_at: 2026-10-01 17:00
import sys
from collections.abc import Iterator
def prime_powers(n: int) -> Iterator[tuple[int, int]]:
"""把 n 分解质因数,依次产出 (质因子 p, 指数 a),即 n = ∏ p^a。"""
p = 2
while p * p <= n:
if n % p == 0:
a = 0
while n % p == 0:
n //= p
a += 1
yield p, a
p += 1
if n > 1: # 除完所有 ≤ √n 的因子后还剩的大于 1 的部分必然是质数
yield n, 1
def answer(n: int) -> int:
"""求 ∑_{1 ≤ i ≤ n} gcd(i, n):答案关于 n 是积性的,在每个质因子幂上乘一个局部因子。"""
total = 1
for p, a in prime_powers(n):
total *= p ** (a - 1) * (p + a * (p - 1))
return total
def solve() -> None:
n = int(sys.stdin.buffer.read()) # 输入只有一个整数 N
print(answer(n))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-01 16:50
* update_at: 2026-10-04 22:12
*/
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
// 返回 f(N) = sum_{i=1}^{N} gcd(i,N)
// 利用积性:f = id * phi,对质因子幂 p^a,局部因子为 p^{a-1} * (p + a*(p-1))
ll solve(ll N) {
ll ans = 1;
// 试除法分解质因数,O(sqrt(N))
for (ll p = 2; p * p <= N; ++p) {
if (N % p == 0) {
ll a = 0;
ll pw = 1; // p^a
while (N % p == 0) {
N /= p;
++a;
pw *= p;
}
// 局部因子:p^{a-1} * (p + a*(p-1))
// pw 已经是 p^a,所以 p^{a-1} = pw / p
ll part = (pw / p) * (p + a * (p - 1));
ans *= part;
}
}
// 剩余一个大于 sqrt(原N) 的质因子
if (N > 1) {
// 此时 a = 1, p = N, p^{a-1} = 1, 局部因子 = 1 * (N + 1*(N-1)) = 2*N - 1
ll part = 2 * N - 1;
ans *= part;
}
return ans;
}
int main() {
ll N;
scanf("%lld", &N);
printf("%lld\n", solve(N));
return 0;
}复杂度
- 时间复杂度:
。 - 空间复杂度:
。
总结
- 「gcd 之和」类问题的标准变形:按
取值分组,化为 。 - 记住
是积性函数,质因子幂上的局部因子 可直接套用。 - 单个
时无需线性筛, 试除分解质因数即可。