PKU 3370 Halloween treats 【鸽笼定理】
分类: 数论 2010-08-20 19:21 127人阅读 评论(0) 收藏 举报
【题目地址】
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)的时间就判断出了结果。
#include<stdio.h>
#include<string.h>
const int N=1000005;
int a[N],mod[N];//mod[]记录,余数为0,1,2,。。。n-1的下标
int n,m;
int main()
{
int i,sum,len,pos;
while(scanf("%d%d",&n,&m),m+n)
{
memset(mod,-1,sizeof(mod));
sum=0;
len=0;
pos=0;
for(i=0;i<m;i++)
{
scanf("%d",&a[i]);
if(len)continue;//若len!=0表示找到了
sum=(sum+a[i])%n;//前k项对n的余数
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<pos+len;i++)
{
printf(" %d",i+1);
}
printf("\n");
}
}