Vijos1090. 連續數之和

試題請參見: https://vijos.org/p/1090

題目概述

有n個正整數排成一行。你的目的是要從中取出一個或連續的若干個數,使它們的和能夠被k整除。
例如,有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和k。輸入數據保證有n<=500 000,k<=100 000。
以下n行每行一個正整數。這些正整數保證都不大於10 000。

輸出

一個正整數。它應該是你的答案mod 1234567的結果。

解題思路

假設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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章