【題目地址】
http://acm.pku.edu.cn/JudgeOnline/problem?id=3370
【題目大意】
萬聖節鄰居i會發給孩子們一定數量的糖果a[i],現在有c個孩子和n戶鄰居(1<=c<=n<=100000), 爲了不引起糾紛,孩子們決定選擇性的去某些鄰居家索要糖果,使得到的糖果總數可以均分給n個人(只要均分就行,不要求糖果數最多)。
【解題思路】
基本原理:如果n+1個物體放進n個盒子,那麼至少有一個盒子包含兩個或者更多的物體。考慮一個問題:給出n個數,從中選出若干數使他們的和爲n的倍數。
結論:存在若干連續數,它們的和是n的倍數。
證明:設S(k)=a(1)+a(2)+···+a(k).如果存在一個S(k)是n的倍數,那麼把前k個數選出來就可以了。否則所有n個S(k)(n個物體)除以n的餘數只有1,2,3,···,n-1中可能(n-1個盒子),但現在有n個S(k)(n個物體),由基本原理知,必然有兩個不同的和S(i)和S(j)(i<j)除以n的餘數相同,故部分和S(j)-S(i)=a(i+1)+···+a(j)是n的倍數。
本題暴力肯定TLE,考慮鴿籠定理:從n個數中取出若干,和爲c(c<=n)的倍數。
看另外一個例子:
一個屋子裏面有n個人,他們的最大年齡不超過k歲,問是否肯定存在2組人(兩組沒有重複的人),使得這兩組人的年齡和相等。
先看一個簡單的:有5個小朋友,年齡(整數)都在1—4歲之間,那麼至少有兩個人的年齡相同(不要懷疑);
那麼本例中,n個人的組合,一共有2^n(2^n個小朋友)種方法,注意到最大情況n的人的年齡和是n* k(小朋友的年齡在1—n*k之間),這樣如果2^n>n*k,根據鴿籠原理,一定存在兩種組合,他們的年齡和相等,而且沒有重複的人(如果重複,把那個人刪去就行了)。所以 O(1)的時間就判斷出了結果。
此例只是俺的想法,如果有更好的證明方法,歡迎提出。。囧!ACM_DIY羣裏有大牛證明了,看不懂。。
回到POJ 3370 Halloween treats,看代碼(求前S(k)的話int可能溢出,每次取模即可):
【代碼】
-
#include <cstdio>
-
#include <cstring>
-
#define maxn 1000005
-
int m[maxn],mod[maxn];
-
int main()
-
{
-
int c,n,i,sum,len,pos;
-
while(scanf("%d%d",&c,&n)&&c+n){
-
memset(mod,-1,sizeof(mod));
-
for(i=sum=len=0;i<n;i++){
-
scanf("%d",&m[i]);
-
if(len)continue;
-
sum=(sum+m[i])%c;
-
if(sum==0){
-
pos=0;len=i+1;
-
}
-
else if(mod[sum]>=0){
-
pos=mod[sum]+1;
-
len=i-mod[sum];
-
}
-
else
-
mod[sum]=i;
-
}
-
printf("%d",pos+1);
-
for(i=pos+1;i<len+pos;i++)
-
printf(" %d",i+1);
-
printf("/n");
-
}
-
return 0;
-
}