C++實現 藍橋杯 k倍區間

幻想鄉的漏氣威嚴發表於2020-10-04

這裡是題目連結
k倍區間

題目大意
簡單來說,給你一個陣列和一個數k,讓你滿足陣列中連續區間和為k的倍數的區間有幾個

思路
看到題目的連續區間的時候,就知道這題使用字首和來寫的,然後我喜聞樂見的TLE了 ,咳咳,看了題目100000組資料,那n2資料妥妥的過不了了,只能是看看怎麼畫了,於是想到一個定理,(A+B)mod k = A mod k + B mod k。 (A-B)mod k= A mod k - B mod k這樣就有思路了

為了說明方便,我們設這個陣列有{1,2,3,4,5},k為2

首先,對於陣列num, 我們算出它的各個字首和的餘數,然後依此遍歷,設一個計數的陣列cnt[i]表示餘數為 i 的個數,這樣,遍歷過程中,有兩種情況

1.當前元素餘數為1,則此時,由上面的(A-B)mod k =A mod k -B mod k可知,增加的k倍區間個數為cnt[1]的值.簡單來說,cnt[1]為之前找到餘數為1的字首和的個數,如果cnt[1]>0,那麼前面至少有一個餘數為1的字首和,和一個餘數為1的當前的字首和序列,則這兩個序列之間的餘數差為0,則意味著兩個餘數為1的字首和,他們之間的區間就是k倍區間,所以當增加的k倍區間個數有cnt[1]個

2.當前元素餘數為0的情況差不多,增加的k倍區間個數為cnt[0]個

注意到了最後,我們還要格外給答案加上cnt[0]的值,因為餘數為0的字首和本身也是一個k倍區間呀!

那麼剩下的程式碼問題就很簡單了

#include <iostream>

using namespace std;
const int MAXN = 100000+5;
int num[MAXN],cnt[MAXN];

int main() {
	int n,k;
	cin>>n>>k;
	for(int i=0; i<n; i++) {
		cin>>num[i];
	}
	num[0]%=k;
	for(int i=1;i<n;i++){
		num[i]=(num[i]+num[i-1])%k;
	}
//	for(int i=0;i<n;i++){
//		printf("num[%d]=%d\n",i,num[i])
//	}
	long long ans=0;
	for(int i=0;i<n;i++){
		ans+=(cnt[num[i]]);
		cnt[num[i]]++;
//		printf("cnt[%d]=%d ans=%d\n",num[i],cnt[num[i]],ans);
	}
	cout<<ans+cnt[0]<<endl;
	return 0;
}

相關文章