抽屉(鸽巢)定理小结

来源:互联网 发布: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
原创粉丝点击