poj 2356 Find a multiple(鸽巢原理)

来源:互联网 发布:qq酷双项淘宝客 编辑:程序博客网 时间:2024/05/22 08:27

题意:给出一个数N,接着再给出N个数,要你从这N个数中任意选择1个或多个数,使得其和是N的倍数。

如果找不到这样的答案 则输出0。

答案可能有多个,但智勇任意输出一个解就行。

输出的第一行是选择元素的个数M,接着M行分别是选择的元素的值

思路:刚开始的时候并不同为什么这一题回事抽屉原理,分析后才有体会,实际上此题一定有解,不存在输出0的结果。

证明如下:

我们可以依次求出N个数中部分数字组合的情况(实际上组合的数目比下列这些多):a[0],a[0]+a[1],a[0]+a[1]+a[2],......,a[0]+a[1]+a[2]...+a[n];

假设分别是sum[0],sum[1],sum[2],......,sum[n]

如果在某一项存在是N的倍数即sum[i]%N=0,可直接从第一项开始直接输出答案。

但如果不存在,则sum[i]%N的值必定在[1,N-1]之间,又由于有n项sum,有鸽巢(抽屉)原理:

 把多于n个的物体放到n个抽屉里,则至少有一个抽屉里有2个或2个以上的物体。

这里sum[i]%N的余数为巢,即N个巢,数字组合的数目为鸽子,即鸽子数目大于N个。

则必定有一对i,j,使得sum[i]=sum[j],其中i!=j,不妨设j>i

则(sum[j]-sum[i])%N=0,故sum[j]-sum[i]是N的倍数。

则只要输出从i+1~j的所有的a的值就是答案。

然后就利用这个思路就可以直接的解出该题的答案。

#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;int a[10000] ;int mod[10000] ;//mod存储判断sum%n是否出现过,如果没出现时-1,如果出现,则是此时sum对应的k值,即前k项和int sum [10001];//sum存储的与描述略有不同,sum[k]=a[0]+a[1]+...+a[k-1];int main(){    int n ;    int i ;    while ( cin >> n )    {        memset ( mod , -1 , sizeof ( mod ) ) ;        sum[0]=0;        for ( i = 0 ; i < n ; i ++ )        {            cin >> a[i] ;        }        for ( i = 0 ; i < n ; i ++ )        {            sum[i+1]=sum[i]+a[i];            if ( sum [i+1] % n == 0 )            {                //如果是N的倍数,则输出                int j ;                cout<<i+1<<endl;                for ( j = 0 ; j <= i ; j ++ )                    cout<<a[j]<<endl;                break;            }            if ( mod[sum [i+1] % n]!=-1)            {                //如果找到两个数的余数相同,则依次输出                int j ;                cout<<i-mod[sum [i+1] % n]<<endl;                for ( j = mod[sum [i+1] % n]+1 ; j <= i ; j ++ )                    cout<<a[j]<<endl;                break;            }            mod[sum [i+1] % n]=i;//将此时对应的余数存到mod中,值为此时的i        }    }    return 0;}
0 0
原创粉丝点击