【鸽巢原理】POJ 2356 Find a multiplet

来源:互联网 发布:福能集团怎么样 知乎 编辑:程序博客网 时间:2024/06/05 18:55

题目链接: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 longint 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;}






0 0
原创粉丝点击