試題請參見: https://vijos.org/p/1090
題目概述
例如,有6個正整數,它們依次爲1、2、6、3、7、4。若k=3,則你可以取出1、2、6,或者2、6、3、7,也可以僅僅取出一個6或者3使你所取的數之和能被3整除。當然,滿足要求的取法不止以上這4種。事實上,一共有7種取法滿足要求。
給定n和k,以及這n個數。你的任務就是確定,從這n個數中取出其中一個數或者若干連續的數使它們的和能被k整除有多少方法。
由於取法可能很多,因此你只需要輸出它mod 1234567的值即可。
輸入
以下n行每行一個正整數。這些正整數保證都不大於10 000。
輸出
解題思路
假設sum[i]表示前i個數的和.
當(sum[i] - sum[j]) mod k == 0 這時[j + 1, i]就是滿足的一個方案了.
而我們求的是(sum[i] - sum[j]) mod k == 0 這樣的方案總個數, 則有 sum[i] mod k == sum[j] mod k. 即求得滿足sum[i] mod k == sum[j] mod k的方案個數.
假設 sum[a], sum[b], ..., sum[c](共complements[i]個)都是 mod k 餘數爲i的sum;
那麼從上面complements[i]個sum中任意選取兩個就能得出(sum[i] - sum[j]) mod k == 0.
那麼在complements[i]個sum中怎麼配對呢?
1. sum[b1]與sum[b2] sum[b3] ...sum[bn] (bn-1 個)
2. sum[b2]與sum[b3] sum[b4] ...sum[bn] (bn-2 個)
3. sum[b3]與sum[b4] sum[b5] ...sum[bn] (bn-3 個)
............
n-1. sum[bn-1]與sum[bn] ( 1 個)
所以對於餘數爲i的情況, 方案總數= (n-1) + (n-2) + (n-3) + ... + 1 = complements[i] * ( complements[i] - 1 ) / 2.
遇到的問題
1. 若干次的WA, 由於沒有考慮到當餘數爲0時, 自身也可以構成一種方案, 因此需要加上complements[0].
2. 若干次的TLE, 其實很多事情可以在一個循環內完成.
源代碼
#include <iostream>
int main() {
using std::cin;
int n = 0, k = 0, total = 0;
int complements[100000] = {0};
// Input
cin >> n >> k;
// Processing
int sum = 0, number = 0;
for ( int i = 0; i < n; ++ i ) {
cin >> number;
sum += number % k;
++ complements[sum % k];
}
for ( int i = 0; i < k; ++ i ) {
total = (total + complements[i] * (complements[i] - 1) / 2) % 1234567;
if ( i == 0 ) {
total += complements[i] % 1234567;
}
}
// Output
std::cout << total << std::endl;
return 0;
}