【鸽巢原理】POJ 2356 Find a multiplet

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

}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值