標題: 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;
}