抽屉原理
定义:
第一抽屉原理:
原理1: 把多于n个(n+k)的物体放到n个抽屉里,则至少有一个抽屉里的东西不少于两件。
证明(反证法):如果每个抽屉至多只能放进一个物体,那么物体的总数至多是n×1个,而不是题设的n+k(k≥1),故不可能。
原理2 :把多于(m*n)+1(n不为0)个的物体放到n个抽屉里,则至少有一个抽屉里有不少于(m+1)的物体。
证明(反证法):若每个抽屉至多放进m个物体,那么n个抽屉至多放进mn个物体,与题设不符,故不可能。
原理3 :把无穷多件物体放入n个抽屉,则至少有一个抽屉里 有无穷个物体。
原理1 、2 、3都是第一抽屉原理的表述。
第二抽屉原理
把(m*n-1)个物体放入n个抽屉中,其中必有一个抽屉中至多有(m—1)个物体。
[证明](反证法):若每个抽屉都有不少于m个物体,则总共至少有mn个物体,与题设矛盾,故不可能
经典例题:
题目:
输入n,给你n个数,从中找到 m个连续的数, 1<=m<=n,使得这m个数的和是n的倍数;如果找不到输出0;
解析:
我们先用一个sum数组,存取数的连续和。
如果sum[i]能否整除n,如果能则输出下标,然后直接从第一个数开始依次输出即可。
关键:如果不存在上面的那种情况
因为sum[i]%n一定是属于【1~n-1】的,而sum总共有n个,根据鸽巢定理
把多于n个的物体放到n个抽屉里,则至少有一个抽屉里有2个或2个以上的物体。
所以n个 sum【i】%n中,至少有两个是一样的;(此题一定有解,不存在输出0的情况)
如果我们找到,则说明sum[i]%n==sum[j]%n, i<j;则i和j之间的数就是答案
代码实现:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
using namespace std;
typedef long long ll;
int n,sum[10005],mod[10005];
int main()
{
while(scanf("%d",&n)!=EOF)
{
sum[0]=0;
memset(mod,0,sizeof(mod));
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
sum[i]=sum[i-1]+x;
}
for(int i=1;i<=n;i++)
{
if(sum[i]%n==0)
{
cout<<i<<endl;
for(int j=1;j<=i;j++)
printf("%d\n",sum[j]-sum[j-1]);
break;
}
if(mod[sum[i]%n]!=0)
{
int j=mod[sum[i]%n]+1;
cout<<i-j+1<<endl;
for(;j<=i;j++)
printf("%d\n",sum[j]-sum[j-1]);
break;
}
mod[sum[i]%n]=i;
}
}
return 0;
}
经典例题: