鸽巢原理:hdu 1205 吃糖果+poj 2356 Find a multiple+poj 3370 Halloween treats
来源:互联网 发布:类似淘宝的交易平台 编辑:程序博客网 时间:2024/05/18 01:36
鸽巢原理
也称抽屉原理,原理简单但应用却很广泛。
**
(一)基本原理
**
**n+1只鸽子飞回n个鸽巢,至少有一个鸽巢含有不少于2只的鸽子。
另一种表述:假如有n+1个元素放到n个集合中,其中必定至少有一个集合里有2个元素**
hdu 1205 吃糖果(基本原理)
题目大意
给定n种类型的糖果各自的数量,问吃糖果时能不能不是连续吃到同一种糖果。
解题思路
1.插空法,找到数量最多的糖果,假设有n个,则有n+1个区域(注意是区域,不仅仅能放一个元素哦!)可以填放其他类型的糖果,很容易猜到只要其他种类糖果之和小于等于n-1(中间的空),就可以满足条件。
X_X_X_X_X_X_X
2那么,为什么正确呢?这里用到了抽屉原理(鸽巢原理)。
假设有一种糖果在插孔的过程中出现了相邻的情况(我们的目的是不让他们相邻,出现一个就放入一个空里,所有糖果都这么处理,所以只需分析其中的一种糖果),那么所有的空都填满,数量>=n+1+1个才能出现相邻的情况(这句话体现了鸽巢原理!),此时与最多数量为n的假设矛盾!所以不会出现相邻的情况
即这道题只要满足其他类型糖果数量比n-1个空多就可以。
参考代码
#include <iostream>#include <cstdio>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <cmath>#define eps 1e-8using namespace std;typedef long long ll;const int maxn = 1e2+10;int main(){ // freopen("input.txt","r",stdin); int T;scanf("%d",&T); while(T--){ int n;scanf("%d",&n); ll sum=0; int num,Max=-1; for(int i=0;i<n;i++){ scanf("%d",&num); sum+=num; Max=max(Max,num); } sum-=Max; //除了数目最大的糖果外其他糖果的个数 Max-=1; //表示插空法中空的个数-2 if(sum>=Max) printf("Yes\n"); else printf("No\n"); } return 0;}
//////////////////////////////////华丽的分割线///////////////////////////////////////
(二)定理
poj 2356 Find a multiple(定理)
第一遍做直接套用定义,比较容易理解,就是分为证明过程中(1)(2)两种情况,找到就输出结果,并终止循环。
#include <iostream>#include <cstdio>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <cmath>#define eps 1e-8using namespace std;typedef long long ll;const int maxn = 1e4+10;int n,a[maxn],sum[maxn];void solve(){ bool flag=true; for(int i=1;flag&&i<=n;i++) if(sum[i]==0){ printf("%d\n",i); for(int j=1;j<=i;j++) printf("%d\n",a[j]); flag=false; } else{ for(int j=1;j<i;j++) if(sum[i]==sum[j]) { printf("%d\n",i-j);//输出字符串个数 for(int k=j+1;k<=i;k++) printf("%d\n",a[k]); flag=false; break; } } return;}int main(){ // freopen("input.txt","r",stdin); while(scanf("%d",&n)!=EOF){ sum[0]=0; //初始化部分,读入数据 for(int i=1;i<=n;i++){ scanf("%d",a+i); sum[i]=(sum[i-1]+a[i]%n)%n; } solve(); } return 0;}
poj 3370 Halloween treats(定理)
基本上是一样的题,如果同样用定义实现的话,查找会TLE的。
建议使用标记数组flag[]来实现,找到就标记当前位置,再次标记时就直接输出所求序列即可,查找时就不用二重循环了,只要初始化标记数组置0就好。
还有,建议求和数组值先取模,一是取模很耗时,二是先取模不会溢出数据,3370这道题数据比较强,容易溢出。
参考代码
#include <iostream>#include <cstdio>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <cmath>#define eps 1e-8using namespace std;typedef long long ll;const int maxn = 1e5+10;int c,n,a[maxn];int sum[maxn];int flag[maxn];int main(){ // freopen("input.txt","r",stdin); while(scanf("%d%d",&c,&n)!=EOF&&c+n){ sum[0]=0; memset(flag,0,sizeof(flag)); for(int i=1;i<=n;i++){ scanf("%d",a+i); sum[i]=(sum[i-1]+a[i]%c)%c; } //初始化部分 for(int i=1;i<=n;i++){ if(sum[i]==0){ for(int j=1;j<=i;j++) j==1?printf("%d",j):printf(" %d",j);puts(""); break; } else if(flag[sum[i]]>0){ for(int j=flag[sum[i]]+1;j<=i;j++) j==i?printf("%d",j):printf("%d ",j);puts(""); break; } else flag[sum[i]]=i; } } return 0;}
(三)推论
- 鸽巢原理:hdu 1205 吃糖果+poj 2356 Find a multiple+poj 3370 Halloween treats
- POJ 2356 Find a multiple / 3370 Halloween treats 鸽巢原理
- poj 3370 Halloween treats&&poj 2356 Find a multiple
- 抽屉定理poj 3370|| hdu1808 Halloween treats || hdu 1205 吃糖果 ||poj 2356
- 鸽巢原理应用-分糖果 POJ 3370 Halloween treats
- POJ 3370 && HDU 1808 Halloween treats(鸽巢原理)
- POJ 3370 Halloween treats 鸽巢原理
- POJ 3370 Halloween treats 鸽巢原理
- POJ 3370 Halloween treats 鸽巢原理
- POJ 3370 Halloween treats - 鸽巢原理
- POJ 3370 Halloween treats【鸽巢原理】
- poj 3370 Halloween treats(反演定理+鸽巢原理)
- POJ 3370 Halloween treats 鸽巢原理 解题
- poj 3370 Halloween treats (组合数学:鸽巢原理)
- POJ 3370 Halloween treats(鸽巢原理)
- POJ 题目3370 Halloween treats(鸽巢原理)
- 数学 ( 鸽巢原理 )——Halloween treats ( POJ 3370 )
- POJ 3370-Halloween treats(鸽巢原理)
- HTTP(S)网站目录暴破测试工具 – Dirs3arch v0.3.0
- Ultra-QuickSort(离散化+树状数组求逆序数)
- 2015年2月11日
- 通用的POI导入Excel解决方案
- 代理实现界面跳转传值
- 鸽巢原理:hdu 1205 吃糖果+poj 2356 Find a multiple+poj 3370 Halloween treats
- 《网络流学习笔记04 && NYOJ 489 哭泣天使(建边,超级源点和汇点)》
- 趣题——打开的锁
- 树状数组 求逆序数
- change the username on ubuntu 12.04 server
- C#基础总结
- windows下编译及使用libevent
- 百度地图 判断一个标注点是否在多边形区域里
- 【Servlet】web.xml中servlet的配置方法