鸽巢原理

鸽巢原理又称抽屉原理
基本原理: n+1只鸽子飞回n个鸽笼,至少有一个鸽笼含有2只
他的数学描述语言为:
m个元素分成n组,那么总有一组至少含有元素个数为 [m/n]
设a1,a2,a3,....am是正整数的序列,试证明至少存在整数k,l, (1=<k<l<=m)
使得和 a(k+1)+a(k+2)+...+a(l)是m的倍数
证明略,但是可以从构造和数列入手,两个余数相同的数相减可以被除数整除

万圣节恶作剧:
在万圣节这天每个小孩都会挨家挨户要糖果,但是邻居们只想给出一定数量的糖果,如果你去的很晚
可能要不到糖果,所以孩子们决定把所有要来的糖放在一起,然后平均分摊,按以往的经验孩子们知道每个用户
会给出多少糖,由于他们更关心要来的糖能否平分,所以他们只选择了一部分住户,这样糖会被平分
又不会有糖果剩下。
输进c和n,c是小孩的个数,n是住户的个数(1<=n<=100 000)
接下来有n个数,分别为住户给出的糖果数ai(1=<ai<=100 000)。
以0 0为标志结束。
对于每组数据,输出孩子们选择的住户的编号,如果有多组,只输出一组即可
否则,输出"no sweets"

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    int c,n,sum,k,l,m;
    int a[100001],S[100001];
    while(cin>>c>>n){
        if(c==0&&n==0) break;
        memset(a,0,sizeof(a));
        memset(S,0,sizeof(S));
        sum=0;
        m=-1;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            sum+=a[i];
            if(sum%c==0&&m==-1)
                m=i;   
        }
        if(m==-1){
        S[n]=sum;
        //寻找两个mod n相等的Si
    for(int i=n-1;i>=1;i--)
        S[i]=S[i+1]-a[i+1];
     for(int i=1;i<=n;i++)
         S[i]%=c;
     for(int i=1;i<=n;i++){
         for(int j=i+1;j<=n;j++){
             if(S[i]==S[j]){
                 k=i;
                 l=j;
                 break;
             }
         }
     }
     for(int i=k+1;i<=l;i++)
         cout<<i<<" ";

    }
    else{    //在累加和的时候就找到啦
        for(int i=1;i<=k;i++)
            cout<<i<<" ";
        cout<<endl;

    }
     }
    return 0;
}
原文地址:https://www.cnblogs.com/wintersong/p/4945878.html