您的位置:首页 > 其它

poj 2356 Find a multiple(鸽巢原理)

2016-05-20 21:46 197 查看
题意:给出一个数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


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

如果在某一项存在是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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: