题目链接:http://poj.org/problem?id=2356
题意:给N个数,问是否能取m个数,使其和为N的倍数
鸽巢原理
所谓鸽巢原理即n+1只鸽子,只有n个巢,则至少有一鸽巢有两只鸽子。
鸽巢原理又叫抽屉原理。
推广:
如果要把n个物件分配到m个容器中,必有至少一个容器容纳至少⌈n / m⌉个物件。(⌈x⌉大于等于x的最小的整数)
对于本题
可以用鸽巢原理来证明:
设\(a_1,a_2,\cdots ,a_n\)是正整数序列,则至少存在整数\(l,r,1\leqslant l<r\leqslant n\),使得\(\sum_{i=l}^{r}a_i\)是n的倍数。
证明:
构造一个序列\(s_n=\sum_{i=1}^{n}\),则\(s_1<s_2<\cdots<s_n\)
有两种可能:
(1)若有一个\(s_h\)是n的倍数,则定理已得证。
(2)设在上面的序列中没有任何一个元素是m的倍数。令$$s_h\equiv r_h (mod n)$$
其中\(h=1,2,\cdots,n\).假定上面的序列中所有的项都非n的倍数,故其中\(r_1,r_2,\cdots,r_n\)无一为0,而 且所有的\(r_h\)均小于n。不超过n
-1的正整数只有n-1个。根据鸽巢原理,其中至少存在一对\(r_h,r_k\),满 足\(r_h=r_k\).即\(s_h\)和\(s_k\)满足$$s_k\equiv s_h (mod n)$$
不妨设\(h>k\).
$$\begin{array}{lcl}&s_h&=a_1+a_2+\cdots+a_k+a_k+1+\cdots+a_h\\-)&s_k&=a_1+a_2+\cdots+a_k\\\hline&s_h-s_k&=a_{k+1}+a_{k+2}+\cdots+a_h\equiv 0 (mod n)\\\end{array}$$
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define INF 1<<30
#define N 10005
#define LL long long
int num[N];
int sum[N];//记录前n项和
int l,r;//记录左右下标
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=1;i<=n;++i){
scanf("%d",&num[i]);
}
sum[0]=0;
for(int i=1;i<=n;++i)
sum[i]=sum[i-1]+num[i];
int flag=0;
for(int i=1;i<=n&&!flag;++i){
for(int j=i;j<=n&&!flag;++j){
if((sum[j]-sum[i-1])%n==0){
l=i,r=j,flag=1;
break;
}
}
}
printf("%d\n",r-l+1);
for(int i=l;i<=r;++i)
printf("%d\n",num[i]);
}
return 0;
}