抽屉(鸽巢)定理小结
来源:互联网 发布:2016年双11淘宝营业额 编辑:程序博客网 时间:2024/06/09 15:42
抽屉定理: “把多于kn个东西任意分放进n个空抽屉(k是正整数),那么一定有一个抽屉中放进了至少k+1个东西。”
虽然这是废话,但是应用起来就相当不容易。
poj 2356 Find a multiple
题意: 给你N个数,从N个数中选出M个数使得这M个数的和是N的倍数,输出M以及这M个数。
思路: 首先求出Sum[1~n] mod N,Sum[i]为前i项和对N取余,如果Sum[i]==0 则前i个数即为所求。如果没有则根据mod的原理,所有的数都在0~N-1之间,而且没有0,则所有的结果都在1~N-1之间。这就好比有N个数,其结果有N-1种,则必有两个结果相等。也就说明必有两个数mod N相等,则这两个数相减的值必是N的倍数。
#include"cstdlib"#include"cstdio"#include"cstring"#include"cmath"#include"queue"#include"algorithm"#include"iostream"using namespace std;struct node{ int id,sum,x;};int cmp(node a,node b){ if(a.sum==b.sum) { if(a.id<b.id) return 1; return 0; } if(a.sum<b.sum) return 1; return 0;}int main(){ int n; while(cin>>n) { int i,j; node a[12345]; int y[12345]; memset(a,0,sizeof(a)); for(i=1; i<=n; i++) { scanf("%d",&a[i].x); y[i]=a[i].x; a[i].id=i; a[i].sum=a[i-1].sum+a[i].x; } for(i=1; i<=n; i++) { a[i].sum%=n; if(a[i].sum==0) { printf("%d\n",a[i].id); for(j=1; j<=a[i].id; j++) printf("%d\n",a[j].x); break; } } if(i!=n+1) continue; sort(a+1,a+1+n,cmp); for(i=1;i<n;i++) { if(a[i].sum==a[i+1].sum) { printf("%d\n",a[i+1].id-a[i].id); for(j=a[i].id+1;j<=a[i+1].id;j++) printf("%d\n",y[j]); break; } } }}
poj 3370 Halloween treats
同上类似,就不说了,注意输出的是下标而不是具体的数。
poj 3145 Harmony Forever
题意:给你一个集合S,初始是空集。有两种操作,B X 代表把X元素加入到S集合之中,A M,询问集合S中mod M 最小的元素的下标,没有的话输出-1,如果同样小输出最后加进来的那个数的下标。
思路:根据抽屉定理,余数一定在0~M-1之间。这样的话我们把范围进行区间划分为(0,,M-1),(M,2*M-1)...依次类推,这样找出每个区间内的最小值,而这些最小值的最小值就是所求的答案。
这里的区间查找可以使用线段树来维护,但是当M<=5000时,爆搜的速度会比线段树来的快!
#include"cstdlib"#include"cstdio"#include"cstring"#include"cmath"#include"queue"#include"algorithm"#include"iostream"#define inf 999999999using namespace std;int ans[40002];struct tree{ int l,r; int m,id;} a[500002*4];void build(int k,int l,int r){ a[k].l=l; a[k].r=r; a[k].m=inf; a[k].id=0; if(a[k].l==a[k].r) return; build(k*2,l,(r+l)/2); build(k*2+1,(r+l)/2+1,r);}void add(int k,int x,int y,int z){ if(a[k].l==x&&a[k].r==x) { a[k].m=y; a[k].id=z; return; } int mid=(a[k].l+a[k].r)/2; if(x<=mid) add(k*2,x,y,z); else add(k*2+1,x,y,z); if(a[k*2].m<a[k*2+1].m) { a[k].m=a[k*2].m; a[k].id=a[k*2].id; } else { a[k].m=a[k*2+1].m; a[k].id=a[k*2+1].id; }}tree query(int k,int l,int r){ if(a[k].m==inf) return a[k]; if(a[k].l==l&&a[k].r==r) return a[k]; int mid=(a[k].l+a[k].r)/2;; if(r<=mid) return query(k*2,l,r); else if(l>mid) return query(k*2+1,l,r); else { tree x=query(k*2,l,mid); tree y=query(k*2+1,mid+1,r); if(x.m<y.m) return x; else return y; }}int main(){ int t,cas=1; while(scanf("%d",&t),t) { int cont=1; int MAX=-1; build(1,0,500002); if(cas!=1) puts(""); printf("Case %d:\n",cas++); while(t--) { char x[12]; scanf("%s",x); if(x[0]=='B') { int y; scanf("%d",&y); if(y>MAX) MAX=y; add(1,y,y,cont); ans[cont++]=y; } else { int m; scanf("%d",&m); if(MAX==-1) { puts("-1"); continue; } if(m<=5000) { int Min=inf; int mini; for(int i=cont-1; i>=1; i--) { if(ans[i]%m<Min) { Min=ans[i]%m; mini=i; } if(Min==0) break; } printf("%d\n",mini); } else { int Min=inf; int mini=-1; int l,r; l=0; r=m-1; while(l<=MAX) { if(r>MAX) r=MAX; tree cur=query(1,l,r); if(cur.m==inf) //这个条件不加无限WA... { l+=m; r+=m; continue; } if(cur.m%m<Min) { Min=cur.m%m; mini=cur.id; } else if(cur.m%m==Min) { if(cur.id>mini) mini=cur.id; } l+=m; r+=m; } printf("%d\n",mini); } } } }}
0 0
- 抽屉(鸽巢)定理小结
- 容斥定理与鸽巢定理(抽屉定理)
- hdu 5776 抽屉定理
- poj 2356 find a multiple(抽屉定理)
- 51nod 1103 N的倍数(抽屉定理)
- 51nod 1103 N的倍数(抽屉定理)
- Codeforces 850 A. Five Dimensional Points(暴力/抽屉定理)
- polya 定理小结 (转)
- 抽屉菜单使用小结
- 数论四大定理小结(初级)
- 中国剩余定理(CRT)学习小结
- Codeforces Round #334 (Div. 2) E(抽屉原理+逆元+费马小定理 )
- Hdu5776 sum 抽屉原理+同余定理
- polya定理再小结
- Polya定理小结
- polya定理再小结
- lucas定理小结
- polya定理小结
- spring源码之spring启动三
- get the base application URL?
- php正则去掉全半角标点及空白
- Android截取字段和字符串
- 使用Flash骨骼工具制作角色动画
- 抽屉(鸽巢)定理小结
- Fedora常用软件安装
- tarjan+缩点
- iOS 7教程-Storyboards Part1
- hdu 1535 Invitation Cards(spfa)
- jquery判断checkbox是否选中及改变checkbox状态
- Unity项目接收不到android的KeyEvent的解决办法
- linux挂载和卸载移动设备
- 解决Android 4.0以上版本中OptionsMenu菜单不显示ICON图标的问题