现在的位置: 首页 > 综合 > 正文

poj 3370 Halloween treats(反演定理+鸽巢原理)

2013年04月23日 ⁄ 综合 ⁄ 共 1185字 ⁄ 字号 评论关闭

题意: 已知有n户人,每户会给小孩们一定数量的糖果(会给的数量假设小孩都已知),求小孩挑选哪几户人家,所得糖果总数能够使每个小孩得到相同数量的糖果,即是小孩数目的倍数?

思路:定理:

         设a1、a2……am是正整数的序列,则至少存在整数k和l,(1<=k<l<=m),使得和a(k+1) + a(k+2) + ... ... +al是m的倍数。

  证明:x%m的余数有(m-1)中可能,即设有(m-1)个鸽巢,设sn代表(a1+a2+...+an)则m个sn产生m个余数,根据鸽巢原理,一定至少有两个s的余数相等,将这连个s想减,中间a(k+1) + a(k+2) + ... ... +al一定是m的倍数。


代码:

#include<iostream>
#include<string.h>
#include<algorithm>
#define N 100010
using namespace std;
struct Sum
{
    int r , h;
};
Sum R[N];

bool cmp(Sum a , Sum b)
{
    if(a.r==b.r) return a.h<b.h;
    return a.r<b.r;
}
int main()
{
    int c , n  , tmp;
    __int64 sum ;
    int flag ,b;
    while(scanf("%d%d",&c,&n)!=EOF && ( n+c ))
    {
        sum=0;  //cout<<"c= "<<c<<"  n= "<<n<<endl; 
        flag=-1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&tmp);
            sum+=tmp;
            //cout<<"sum = "<<sum<<endl;
            R[i].r=sum%c; // cout<<"R["<<i-1<<"].r= "<<R[i-1].r<<endl;
            R[i].h=i;
            if(R[i].r==0 ) flag=i; 
        }
     //   cout<<"flag=  "<<flag<<endl;
        if(flag==-1)
        {
            sort(R+1,R+1+n,cmp);
         //   for(int i=1;i<=n;i++) cout<<R[i].r<<" * ";cout<<endl;
         //   for(int i=1;i<=n;i++) cout<<R[i].h<<" & ";cout<<endl;
            for(int i=1;i<n;i++)  
            {
                if( R[i].r==R[i+1].r) {flag=R[i].h; b=R[i+1].h;} 
            }    
         //   cout<<"a=  "<<flag<<"  b= "<<b<<endl;
            if(flag==-1) printf("no sweets\n"); 
            else
            {
               for(int j=flag+1;j<b;j++)  printf("%d ",j);
               printf("%d\n",b); 
            }
        }
        else
        {
            for(int i=1;i<flag;i++) printf("%d ",i);
            printf("%d\n",flag);
        }
      
    }
    return 0;
} 

抱歉!评论已关闭.