第八屆藍橋杯第十題 k倍區間

標題: k倍區間

給定一個長度爲N的數列,A1, A2, … AN,如果其中一段連續的子序列Ai, Ai+1, … Aj(i <= j)之和是K的倍數,我們就稱這個區間[i, j]是K倍區間。

你能求出數列中總共有多少個K倍區間嗎?

輸入

第一行包含兩個整數N和K。(1 <= N, K <= 100000)
以下N行每行包含一個整數Ai。(1 <= Ai <= 100000)

輸出

輸出一個整數,代表K倍區間的數目。

例如,
輸入:
5 2
1
2
3
4
5

程序應該輸出:
6

資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗 < 2000ms

請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入…” 的多餘內容。

注意:
main函數需要返回0;
只使用ANSI C/ANSI C++ 標準;
不要調用依賴於編譯環境或操作系統的特殊函數。
所有依賴的函數必須明確地在源文件中 #include
不能通過工程設置而省略常用頭文件。

提交程序時,注意選擇所期望的語言類型和編譯器類型。

思路

要計算任意兩個區間的和,很容易想到的是前綴和,知道前綴和以後要求區間[l,r]的和可以很容易的通過sum[r]-sum[l-1]的方式來求,但是求完前綴和以後既然要是任意區間,那麼肯定不可以枚舉兩個端點,這樣複雜度就變成了O(n2)O(n2),身爲藍橋杯的壓軸題肯定不可行,我們可以考慮一個變形:
(sum[r]−sum[l−1])%k=sum[r]%k−sum[l−1]%k

等價於
sum[r]%k==sum[l−1]%k

所以我們只需要在求前綴和的時候順便模k,對於最後的結果,如果值爲0,那麼證明這個區間一定是k的倍數,所以這段區間肯定在內,那麼對於不爲0的情況,只要兩個前綴和的值相等,那麼這兩段區間相減也是k的倍數,所以只需要統計一下(類似桶排)相同的前綴和個數,對於這個值n∗(n−1)2n∗(n−1)2就是有多少個區間。
要注意給0這個端點的值+1,因爲計算前綴和的時候,第一個0沒有被計算,是存在區間長度爲1的數據能整除k .

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+5;
int a[maxn];
ll sum[maxn];
int n,k;
ll c[maxn];
ll ans=0;
int main()
{
    cin>>n>>k;
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum[i]=(sum[i-1]+a[i])%k;
    }
    c[0]=1;
    for(ll i=1;i<=n;i++)
        c[sum[i]]++;
    for(ll i=0;i<2;i++)
    {
       ans+=c[i]*(c[i]-1)/2;
    }
    cout<<ans<<endl;
    return 0;
}

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