這是2010年度 CSC3270 的功課...
題意:
給定 N
計算 ∑1≤i≤Ngcd(i, N)
算法:
Ans := 0
Foreach divisor of N, D
Ans += D × Phi( N / D )
EndFor
證明:
留意到 GCD(i, N) 必然是 N 的某個因數
對於 D | N
GCD(x, N) = D 的必然條件是
x = kD, 其中 k 是正整數
然後
GCD(kD, N) = D ⇔ GCD(k, N / D) = 1
實現:
先對 N 進行質因數分解
然後用 DFS 枚舉所有因數 - D
在枚舉 D 的同時
可以利用 歐拉函數 (Euler phi function) 的特性
- Φ(pk) = pk - pk-1 for prime p
- Φ(AB) = Φ(A) × Φ(B) for (A, B) = 1
⇒ 總時間複雜度 = O( # N的因數 )
7 void dfs(int k, long long d, int phi) { // phi : PHI(n / d) 8 if (k==q) { 9 ans += d * phi; 10 return; 11 } 12 for (int i=0; i<=e[k]; i++) { 13 dfs(k+1, d, !i?phi:phi-phi/b[k]); 14 d /= b[k]; 15 phi *= b[k]; 16 } 17 } ... 39 ans = 0; 40 dfs(0, n, 1); 41 printf("%lld\n", ans);
延伸 ── 積性函數:
∑1≤i≤Ngcd(i, N) 積性函數 (Multiplicative function)
即 (a,b) = 1 ⇒ f(ab) = f(a) × f(b)
似曾相識吧?
一個可以令你(?)更好感覺何謂積性的例子... 就是 Euler phi function
相關題目 - GCD - Extreme:
以上兩題要求計算:
我直接沿用 PKU 2480 的 source code
預處理 400000 個答案(每個答案需時 O(因數數目))
結果跑得很慢... 需時 4.708 sec
──第二個 submission 加了優化:
在 sieve 時給每個數字記錄的一個質因數
從而加快 prime factorization
在 sieve 時給每個數字記錄的一個質因數
從而加快 prime factorization
看見有些人 0.05 sec AC...
應該是用了 multiplicativity
GCD - Extreme ── 積性優化:
以上 0.992 sec AC 的程序做了以下的優化:
- 在 prime sieve 時,為每個數記錄一個質因數
- 設 gag[N] := ∑1≤i≤Ngcd(i, N)
然後利用 multiplicativity 計算之:
- 情況 1) N 是 prime power, i.e., N = pe (Base case)
gag[N] := N × (e+1) - N/p × e(證明從略) - 情況 2) N 不是 prime power (其它情況)
設 pe | N (e ≥ 1),其中 e 是對於 p 的最大可能值
可積性 ⇒ gag[N] = gag[N/pe] × gag[pe]
- 情況 1) N 是 prime power, i.e., N = pe (Base case)
- 最後,掃描預處理所有答案
For N := 1 to MAX_N
dp[N] := dp[N-1] + gag[N] - N
EndFor
沒有留言:
發佈留言