抽屉原理

抽屉原理

定义

第一抽屉原理:

原理1 多于n(n+k)的物体放到n个抽屉里,则至少有一个抽屉里的东西不少于两件。

证明(反证法):如果每个抽屉至多只能放进一个物体,那么物体的总数至多是n×1个,而不是题设的n+k(k≥1),故不可能。

原理2 :把多于(m*n)+1n不为0)个的物体放到n个抽屉里,则至少有一个抽屉里有不少于(m+1)的物体。

证明(反证法):若每个抽屉至多放进m个物体,那么n个抽屉至多放进mn个物体,与题设不符,故不可能。

原理3 :把无穷多件物体放入n个抽屉,则至少有一个抽屉里 有无穷个物体。 
原理1 2 3都是第一抽屉原理的表述。

第二抽屉原理

  把(m*n1)个物体放入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 sumi%n中,至少有两个是一样的;(此题一定有解,不存在输出0的情况)

如果我们找到,则说明sum[i]%n==sum[j]%n, i<j;则ij之间的数就是答案

代码实现:

#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;
}

经典例题:

 

HDU 1205 吃糖果

poj 2356 Find a multiple

POJ 3370 Halloween treats

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值