Find a multiple (POJ-2356)(抽屜原理)

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個盒子裏面,一定會有一個盒子有兩個蘋果。

定理: 一個由n個數構成的數列,總能找到若干個連續的數 使它們之和能被n整除。

證明: 對於數列裏面的元素a[1],a[2],...... a[n]。我們可以構造一個數組sum[],用sum[ i ]來存儲前i個元素之和(包括第i個元素)。那麼sum數組裏面所有的元素只有兩種情況:(1) 至少存在一個sum[ i ] 能被n整除;(2) 對於所有的sum[ i ] 都不能被n整除 。

情況(1):定理成立。

情況(2):首先我們知道sum數組裏面有n個元素,又因爲它們都不能被n整除,那麼我們可以得到以下信息:任意的(sum[i] %n)都非0且結果都在(1到n-1範圍裏面)。這樣的話--> n個結果在  1到n-1 範圍內,必然存在兩個相等的結果。而這兩個相同結果所對應的sum[] 之差 必定能被 n整除。

對於抽屜原理,可以有以下拓展:(1) 數列裏面元素個數只要大於或者等於n也成立 (2) 找到的 若干個數 不是連續的也成立。

題意:給你n個數,要你從n個數選出若干個數,要求這若干個數的和是n的倍數,輸出選擇數的個數,以及相應的數。

思路:這道題的話,我們可以依次求出a[0],a[0]+a[1],a[0]+a[1]+a[2],......,a[0]+a[1]+a[2]...+a[n];假設分別是sum[0],sum[1],sum[2],......,sum[n]。如果在某一項存在是N的倍數,則很好解,即可直接從第一項開始直接輸出答案。但如果不存在,則sum[i]%N的值必定在[1,N-1]之間,又由於有n項sum,則必定有一對i,j,使得sum[i]=sum[j],其中i!=j,假設i<j,使得sum[i]%n=sum[j]%n,則(sum[j]-sum[i])%n=0。輸出答案只要出j-i,和a[i+1],a[i+2]……a[j]就可以了。

AC代碼:
 

#include <stdio.h>
#include <string>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
typedef long long ll;
const int maxx=10010;
const int inf=0x3f3f3f3f;
const double eps=1e-5;
using namespace std;
int a[maxx];
int sum[maxx],mod[maxx];//mod[i]記錄sum[i]%n是否出現過,如果以出現,則標記爲出現的初始位置
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            sum[i]=a[i]+sum[i-1];
        }
        for(int i=1; i<=n; i++)
        {//如果是n的倍數,則輸出
            if(sum[i]%n==0)
            {
                printf("%d\n",i);
                for(int j=1; j<=i; j++)
                    printf("%d\n",a[j]);
                break;
            }
            if(mod[sum[i]%n]!=0)
            {//如果找到兩個數的餘數相同,則依次輸出
                printf("%d\n",i-mod[sum[i]%n]);
                for(int j=mod[sum[i]%n]+1; j<=i; j++)
                    printf("%d\n",a[j]);
                break;
            }
            mod[sum[i]%n]=i;//將此時對應的餘數存到mod中,值爲此時的i
        }
    }
    return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章