試題 歷屆試題 k倍區間
資源限制
時間限制:2.0s 內存限制:256.0MB
問題描述
給定一個長度爲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 <xxx>
不能通過工程設置而省略常用頭文件。
提交程序時,注意選擇所期望的語言類型和編譯器類型。
試題分析
k倍區間指Ai,Ai+1,…Aj(i≤j)之和是k的倍數的區間即數列An的[Ai,Aj]範圍內子數列的和爲k的倍數的子數列。那麼可設該和爲sumij,前i項和爲sumi,前j項和爲sumj,且由已知可得sumij=sumj-sumi。
那麼k倍區間就是①sumij%k=0,即(sumj-sumi)%k=0,即sumj%k-sumi%k=0即②sumi%k=sumj%k;到這裏題目也就轉化成對∀i,j∈[1,n]求滿足①或②條件的子數列的個數。這樣先求條件滿足條件②的個數就可以大大的減少計算量
代碼
#include<stdio.h>
int main(){
int n,k;
scanf("%d%d",&n,&k);
int a[n+1],sum[n+1],b[100000]={0},i;
long long ans=0;//ans統計k倍區間的個數
sum[0]=0;//這裏需要初始化一下sum[0]
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=(sum[i-1]+a[i])%k;//sum爲前i個數對k取餘後的值
ans+=b[sum[i]];//b[sum[i]]代表目前值爲sum[i]的個數,ans代表滿足條件②的個數
b[sum[i]]++;//對值爲sum[i]的個數+1
}
printf("%I64d",ans+b[0]);//b[0]代表滿足條件①的個數
return 0;
}