給定整數 n(n ≤ 1,000,000),要求計算 φ(2) + φ(3) + ... + φ(n),其中 φ 為歐拉函數。輸入包含多組測試數據,以 0 結束。
傳統試除法求單個 φ 函數複雜度為 O(√n),多次查詢會超時。採用線性篩法(歐拉篩)可在 O(n) 時間內預處理出所有 φ(i),再構建前綴和陣列 sum[i] = Σ φ(k),每次查詢即為 O(1)。
primes。i,若 phi[i] == 0 則 i 為質數,phi[i] = i-1,加入質數表。p ≤ i 且 i*p ≤ n 的質數 p:
i % p == 0:phi[i*p] = phi[i] * p;break(保證每個合數僅被其最小質因子篩一次)。phi[i*p] = phi[i] * (p-1)。const int MAXN = 1000000;
long long phi[MAXN + 1], sum[MAXN + 1];
vector primes;
void linear_sieve() {
phi[1] = 1;
for (int i = 2; i <= MAXN; ++i) {
if (!phi[i]) {
phi[i] = i - 1;
primes.push_back(i);
}
for (int p : primes) {
if (i * p > MAXN) break;
if (i % p == 0) {
phi[i * p] = phi[i] * p;
break;
} else {
phi[i * p] = phi[i] * (p - 1);
}
}
}
for (int i = 2; i <= MAXN; ++i) sum[i] = sum[i-1] + phi[i];
}
O(MAXN) ≈ 106 操作,極快。phi、sum、primes 共約 20 MB。O(1)。break 條件必須正確,否則會重複更新導致錯誤或退化為 O(n log log n)。phi[1] 定義為 1,但題目求和從 2 開始,故前綴和從 sum[2] 起算。本題是線性篩法求歐拉函數的經典應用。掌握「每個合數僅被最小質因子篩一次」的核心邏輯,即可高效解決大範圍 φ 函數批量計算問題。