鸽巢原理又名抽屉原理
一种简单的表述法为:
- 若有n个笼子和n+1只鸽子,所有的鸽子都被关在鸽笼里,那么至少有一个笼子有至少2只鸽子。
另一种为:
- 若有n个笼子和kn+1只鸽子,所有的鸽子都被关在鸽笼里,那么至少有一个笼子有至少k+1只鸽子。
例子:
- 盒子里有10只黑袜子、12只蓝袜子,你需要拿一对同色的出来。假设你总共只能拿一次,只要3只就可以拿到相同颜色的袜子,因为颜色只有两种(鸽巢只有两个),而三只袜子(三只鸽子),从而得到“拿3只袜子出来,就能保证有一双同色”的结论。
- 有n个人(至少2人)互相握手(随意找人握),必有两人握手次数相同。
一种表达是这样的:如果要把n个物件分配到m个容器中,必有至少一个容器容纳至少⌈n / m⌉个物件。(⌈x⌉大于等于x的最小的整数)
容斥原理又称排容原理
(1)两个集合容斥关系
(2)三个集合容斥关系
(3)n个集合的容斥关系
即1个集合的并-2个集合的并+3个集合的并-4个集合的并+5个集合的并......
鸽巢:
pku2365 Find a multiple
题目意思是给n个数,选择其中一些数,使他们的和是n的k倍,k是自然数。只要输出其中正确的解就行
分析:
这n个数有n个前缀和,s[0],s[1],s[2]...s[n],并且对n取余
如果有s[i]==0,则输出0-i之间的数
如果不存在s[i]==0, 则s[i]一定在[1,n-1]之间 ,
根据鸽巢原理,n个物体放入n-1个盒子,至少有一个盒子有两个及以上的物体,所以题目一定有解
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define maxn 10010 int n; int arr[maxn],s[maxn],h[maxn]; int main() { while(~scanf("%d",&n)) { memset(h,-1,sizeof(h)); int x; for(int i=0;i<n;i++){ scanf("%d",&arr[i]); s[i]=(s[i-1]+arr[i])%n; } int a,b; for(int i=0;i<n;i++) { if(s[i]==0) { a=0; b=i; break; } else{ if(h[s[i]]!=-1) { a=h[s[i]]+1; b=i; break; } else h[s[i]]=i; } } printf("%d\n",b-a+1); for(int i=a;i<=b;i++)printf("%d\n",arr[i]); } return 0; }