範例程式碼已於UVA
、瘋狂程設(CPE)
上皆測試通過。(此題無 ZeroJudge
)
題意
給定 n = ∏ i = 1 m p i a i n=\prod_{i=1}^m p_i^{a_i} n = ∏ i = 1 m p i a i ,求:
f ( n ) = ∑ 1 ≤ x ≤ y ≤ n lcm ( x , y ) = n ( x + y ) f(n)=\sum_{\substack{1 \leq x \leq y \leq n \\ \operatorname{lcm}(x, y)=n}}(x+y)
f ( n ) = 1 ≤ x ≤ y ≤ n lcm ( x , y ) = n ∑ ( x + y )
由於答案可能很大,輸出對 1 0 9 + 7 10^9 + 7 1 0 9 + 7 取餘數的結果。
思路:乘法原理
雖然直覺上就是用乘法原理,但這裡我並沒有詳細證明從一個質因數推廣到多個質因數的過程。可以參考參考資料2.,也許能為你提供一點想法。
公式推導
首先先忽略 x ≤ y x \leq y x ≤ y 的限制,考慮所有的 ( x , y ) (x, y) ( x , y ) 對,由於 lcm ( x , y ) = n \operatorname{lcm}(x, y)=n lcm ( x , y ) = n ,所以除了 ( n , n ) (n, n) ( n , n ) 以外的所有 ( x , y ) (x, y) ( x , y ) 對都會被計算 2 2 2 次。
換句話說,x = y x = y x = y 的情況只會出現在 ( n , n ) (n, n) ( n , n ) 這一對中,其他的 ( x , y ) (x, y) ( x , y ) 對中都存在大小關係。
再來先考慮只有一個質因數的情況,即令 n = p i a i n=p_i^{a_i} n = p i a i ,考慮質因數 p i p_i p i 在 x x x 中的次方數 k k k :
如果 p i p_i p i 在 x x x 中的次方數 k < a i k < a_i k < a i ,那麼 p i p_i p i 在 y y y 中次數必須 = a i = a_i = a i ,此時( x , y ) = ( p i k , p i a i ) (x, y) = (p_i^k, p_i^{a_i}) ( x , y ) = ( p i k , p i a i ) ,故此種情況下 x x x 對 f ( n ) f(n) f ( n ) 的貢獻為 ∑ k = 0 a i − 1 p i k \sum_{k=0}^{a_i-1} p_i^k ∑ k = 0 a i − 1 p i k
如果 p i p_i p i 在 x x x 中的次方數 k = a i k = a_i k = a i ,那麼 p i p_i p i 在 y y y 中次數可以是 0 0 0 到 a i a_i a i ,共 a i + 1 a_i + 1 a i + 1 種情況,此時( x , y ) = ( p i a i , p i k y ) (x, y) = (p_i^{a_i}, p_i^{k_y}) ( x , y ) = ( p i a i , p i k y ) ,故此種情況下 x x x 對 f ( n ) f(n) f ( n ) 的貢獻為 ( a i + 1 ) ⋅ p i a i (a_i + 1) \cdot p_i^{a_i} ( a i + 1 ) ⋅ p i a i
合併兩種情況,得出 x x x 對 f ( n ) f(n) f ( n ) 的貢獻為 ∑ j = 0 a i p i j + a i ⋅ p i a i \sum_{j=0}^{a_i} p_i^j+a_i \cdot p_i^{a_i} ∑ j = 0 a i p i j + a i ⋅ p i a i 。同理,y y y 對 f ( n ) f(n) f ( n ) 的貢獻也是一樣的,故需乘 2 2 2 。 但由於除了 ( n , n ) (n, n) ( n , n ) 以外的所有 ( x , y ) (x, y) ( x , y ) 對都會被計算 2 2 2 次,所以最後答案為 ( ∑ j = 0 a i p i j + a i ⋅ p i a i ) + n (\sum_{j=0}^{a_i} p_i^j+a_i \cdot p_i^{a_i}) + n ( ∑ j = 0 a i p i j + a i ⋅ p i a i ) + n 或是 ( ∑ j = 0 a i − 1 p i j + ( a i + 1 ) ⋅ p i a i ) + n (\sum_{j=0}^{a_i-1} p_i^j+(a_i+1) \cdot p_i^{a_i}) + n ( ∑ j = 0 a i − 1 p i j + ( a i + 1 ) ⋅ p i a i ) + n
最後利用乘法原理,擴展到有多個質因數的情況,即 n = ∏ i = 1 m p i a i n=\prod_{i=1}^m p_i^{a_i} n = ∏ i = 1 m p i a i ,答案為 ∏ i = 1 m ( ∑ j = 0 a i p i j + a i ⋅ p i a i ) + n \prod_{i=1}^m (\sum_{j=0}^{a_i} p_i^j+a_i \cdot p_i^{a_i}) + n ∏ i = 1 m ( ∑ j = 0 a i p i j + a i ⋅ p i a i ) + n 。
實作過程
雖然推出了公式,但直接寫肯定是會 TLE 的,我們不能傻傻的一項一項算。
由於要從 a i 0 a_i^0 a i 0 算到 a i a i a_i^{a_i} a i a i ,每一項都會算到,因此我們可以保留前一項的結果,這樣就可以在 O ( a i ) O(a_i) O ( a i ) 的時間內算出 ∑ j = 0 a i p i j + a i ⋅ p i a i \sum_{j=0}^{a_i} p_i^j+a_i \cdot p_i^{a_i} ∑ j = 0 a i p i j + a i ⋅ p i a i 。
此外,在計算過程中也要記得取餘數,避免數字過大。
時間複雜度為:O ( C × a ) O(C \times a) O ( C × a ) ,其中 C C C 為質因數個數,a a a 為質因數中最大的次方數,對於每個詢問。
空間複雜度為:O ( C ) O(C) O ( C ) ,輸入使用的空間 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 MOD = 10 **9 + 7 T = int (input ()) for tc in range (1 , T+1 ): C = int (input ()) PA = [list (map (int , input ().split())) for _ in range (C)] ans, n = 1 , 1 for (p, a) in PA: sigma, cur = 1 , 1 for _ in range (1 , a+1 ): cur = (cur * p) % MOD sigma = (sigma + cur) % MOD ans *= (sigma + a * cur) % MOD n *= cur ans = (ans + n) % MOD print ("Case %d: %d" % (tc, ans))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <bits/stdc++.h> using namespace std;using LL = long long ;const int MOD = 1e9 + 7 ;const int N = 20 ;int main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); cout.tie (nullptr ); int T, C; LL n, ans, sigma, cur; LL P[N], A[N]; cin >> T; for (int t=1 ; t<=T; t++) { cin >> C; for (int i=0 ; i<C; i++) { cin >> P[i] >> A[i]; } ans = 1 ; n = 1 ; for (int i=0 ; i<C; i++) { sigma = 1 ; cur = 1 ; for (int j=1 ; j<=A[i]; j++) { cur *= P[i]; cur %= MOD; sigma += cur; sigma %= MOD; } sigma += A[i] * cur % MOD; ans *= sigma % MOD; ans %= MOD; n *= cur; n %= MOD; } ans = (ans + n) % MOD; cout << "Case " << t << ": " << ans << endl; } return 0 ; }
參考資料
https://www.cnblogs.com/LLTYYC/p/11496596.html
https://www.luogu.com.cn/article/z4xq670e
其中的 getQ ( 1 , a i , p i + 1 ) \operatorname{getQ}(1, ai, pi + 1) getQ ( 1 , ai , p i + 1 ) 即為 ∑ j = 0 a i p i j \sum_{j=0}^{a_i} p_i^j ∑ j = 0 a i p i j 。
寫在最後
Cover photo is remixed from @SuiginToxic , thanks for their work!
個人認為這題是這次考試中最難的一題,但難點主要在公式推導,實作上並不困難。數學,我的一生之敵。