poj2356 - 抽屉原理

Find a multiple

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 9546 Accepted: 4078 Special Judge

Description

The input contains N natural (i.e. positive integer) numbers ( N <= 10000 ). Each of that numbers is not greater than 15000. This numbers are not necessarily different (so it may happen that two or more of them will be equal). Your task is to choose a few of given numbers ( 1 <= few <= N ) so that the sum of chosen numbers is multiple for N (i.e. N * k = (sum of chosen numbers) for some natural number k).

Input

The first line of the input contains the single number N. Each of next N lines contains one number from the given set.

Output

In case your program decides that the target set of numbers can not be found it should print to the output the single number 0. Otherwise it should print the number of the chosen numbers in the first line followed by the chosen numbers themselves (on a separate line each) in arbitrary order.

If there are more than one set of numbers with required properties you should print to the output only one (preferably your favorite) of them.

Sample Input

5
1
2
3
4
1

Sample Output

2
2
3

思路:

抽屉原理:

桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面至少放两个苹果。这一现象就是我们所说的“抽屉原理”。 抽屉原理的一般含义为:“如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有n+1个元素放到n个集合中去,其中必定有一个集合里至少有两个元素。” 抽屉原理有时也被称为鸽巢原理。它是组合数学中一个重要的原理。

 先求出前i个数的和sum[i],然后一个for循环判断一下是否有sum[i]%n==0的情况,如果有,则输出a[1]到a[i]

如果没有:

那么sum[1]-sum[n]都满足sum[i]%n属于[1,n-1],这可以看成是有n-1个抽屉,n个苹果(sum[1到n],一共n个值,每个值%n后的结果会落到[1,n-1]区间,就算是前n-1个数%n的结果两两都不相等,也就是把前n-1个苹果放到n-1个抽屉里,那么sum[n]%n也一定会和前n个数中其中一个sum[i]%n的值相等的),则至少有两个sum值余n的结果是相同的。

(sum[i]%n=sum[j]%n,i!=j)

这样一来从第i+1个数到第j个数的和就肯定是n的倍数了,而且肯定存在。sum[j]至少比sum[i]大了一倍的n

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=10015,mod=32767;

int sum[N],a[N];
int main(){
    int n,flag=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
        if(sum[i]%n==0)flag=i;
    }
    if(flag){
        printf("%d\n",flag);
        for(int i=1;i<=flag;i++){
            printf("%d\n",a[i]);
        }
        return 0;
    }
    int i,j;
    flag=0;
    for(i=1;i<n;i++){
        for(j=i+1;j<=n;j++){
            if(sum[j]%n==sum[i]%n){
                flag=1;
                break;
            }
        }
        if(flag)break;
    }
    printf("%d\n",j-i);
    for(int k=i+1;k<=j;k++){
        printf("%d\n",a[k]);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值