1. 程式人生 > >藍橋杯:2017年第八屆藍橋杯省賽B組第十題—PREV-40K倍區間

藍橋杯:2017年第八屆藍橋杯省賽B組第十題—PREV-40K倍區間


膜拜這位大佬

做法:首先統計字首和sum[i] 表示A1+A2+…+Ai.所以對於任意一段區間[l,r]的和就是sum[r]-sum[l-1].如果要保證這個區間和為K倍數就是:(sum[r]-sum[l-1])%k == 0.變形後就是:sum[r]%k==sum[l-1]%k,所以我們計算字首和的時候順帶模K,然後統計字首和中相同的資料就行了。複雜度O(n).注意資料可能會溢位!!


作者:YzlCoder
來源:CSDN
原文:https://blog.csdn.net/y1196645376/article/details/69718192

 

巧妙地轉換成了求字首和,並找出相同值對數。需要注意的是如果字首和取模K等於0,那麼這個字首範圍就是一個K倍區間。所以找出所有相同對數後需要加上字首和等於零的個數!

線性時間找出相同對數的方法,出現一個數,加上這個數以前出現的次數,然後再讓它的出現次數加一。很巧妙的實現了當出現兩次時,記錄1次;出現三次時記錄1+2次;出現四次時記錄1+2+3次;剛好是兩兩一對得到的總和!

還需要注意的是記錄對數的變數可能溢位,須用long long int/%lld


#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define SPMAX 100005
int main(int argc,char **argv)
{
	int cnt,k,sp[SPMAX]={0};
	scanf("%d%d",&cnt,&k);
	int sum=0;
	for(int i=0;i<cnt;i++)
		scanf("%d",&sp[i]);
	sp[0]%=k;
	for(int i=1;i<cnt;i++)
		sp[i]=(sp[i]+sp[i-1])%k;
	int book[SPMAX]={0};
	long long int ans=0;
	for(int i=0;i<cnt;i++)
		ans+=(book[sp[i]]++);
	printf("%lld\n",ans+book[0]);
	return EXIT_SUCCESS;
} 

這方法真的是太6啦。。666

 

END