練習】k倍區間(思維,陣列)
阿新 • • 發佈:2018-12-14
題幹:
問題描述
給定一個長度為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
解題報告:
首先看到連續區間想到字首和,看到資料範圍想想,可否滿足某個遞推關係,即:知道了某一個區間是k倍區間,相應的可以推出另外的區間也是k倍區間。或者,預處理出某些值,方便得到我們想要的結果。
可以想出,mod k 同餘的兩段區間合併起來肯定是%k==0的,所以我們預處理出字首和的餘數。程式碼就不難寫了。
AC程式碼:(大一的程式碼了、、、懷念逝去的時光啊!順便吐槽一下當時寫程式碼的稚嫩)
#include<iostream> using namespace std; int yu[1000005]; int a[1000005]; int main() { int n,k; long long int cnt=0;//用int有一個案例過不了 scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i]=(a[i]+a[i-1])%k; //一般的字首和 a陣列 要開longlong,因為他是累加的和啊!可能很大呢!這也給我們個提示,需要在這裡同時進行求餘 yu[a[i]]++; //這也是為什麼i從1開始而不從0開始的原因、 } for(int i=0;i<k;i++){ //cnt+=( yu[i] * (yu[i]-1))/2; //cnt+=(yu[i]*yu[i-1])/2; cnt+=( (yu[i]/2.0) * ( (yu[i]-1)/2.0 ))*2; //cnt+=( (yu[i]/2) * ( (yu[i]-1)/2 ))*2; } cnt+=yu[0]; printf("%lld",cnt); return 0 ; } //5 2 //1 //2 //3 //4 //5
AC程式碼2:(標解)
#include<iostream> using namespace std; typedef long long ll; ll bk[100010] = {0}; ll arr[1000010]; int main() { int n,k; scanf("%d%d",&n,&k); for(int i = 0; i < n; i++) scanf("%lld",&arr[i]); arr[0] %= k; ll sum = 0; for(int i = 1; i < n; i++) arr[i] = (arr[i]+arr[i-1])%k; for(int i = 0; i < n; i++) sum += (bk[ arr[i] ]++); printf("%lld",sum+bk[0]); return 0; }