抽屉原理

五个物品分给四个人,保证每个人都能够分得物品,那么一定有一个人会分得两个物品。

这就是我们所说的抽屉原理

抽屉原理的一般含义为:“如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有n+1或多于n+1个元素放到n个集合中去,其中必定至少有一个集合里有两个元素。” 抽屉原理有时也被称为鸽巢原理(“如果有五个鸽子笼,养鸽人养了6只鸽子,那么当鸽子飞回笼中后,至少有一个笼子中装有2只鸽子”)。它是组合数学中一个重要的原理。

 

  •   原理1:把多于n个的物体放到n个抽屉里,则至少有一个抽屉里的东西不少于两件。
  •   [证明](反证法):如果每个抽屉至多只能放进一个物体,那么物体的总数至多是n,而不是题设的n+k(k≥1),这不可能。
  •   原理2:把多于mn(m乘以n)个的物体放到n个抽屉里,则至少有一个抽屉里有不少于m+1的物体。
  •   [证明](反证法):若每个抽屉至多放进m个物体,那么n个抽屉至多放进mn个物体,与题设不符,故不可能。
  •   原理3:把无穷多件物体放入n个抽屉,则至少有一个抽屉里 有无穷个物体。

 

示例:

1:Find a multiple

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.

 

输入包含n个自然(即正整数)数(n<=10000)。每个数字都不超过15000。这些数字并不一定不同(因此可能会发生两个或更多个数字相等的情况)。你的任务是选择几个给定的数(1<=少数<=n),这样,对于n,所选数的和是倍数(即对于某个自然数k,n*k=(所选数的和))。

输入

输入的第一行包含单个数字n。接下来的n行中的每一行都包含给定集合中的一个数字。

输出

如果程序确定找不到目标数字集,则应将单个数字0打印到输出中。否则,它应该以任意顺序打印第一行中所选号码的号码,后跟所选号码本身(每行单独一行)。

如果有多个具有所需属性的数字集,则应仅将其中一个(最好是您最喜欢的)打印到输出。

 


Sample Input
5
1
2
3
4
1
Sample Output
2
2
3

题意:

给定一个n,接下来输入n个数,对于这n个数,我们选择从i到j的区间(i和j在1-n范围内),满足区间内的所有数字的和是n的倍数,如果存在的话就输出区间内下标,每个数字占一行。

题解:

令sum【i】为前i项和,则sun【i】%n的结果在【1,n-1】之间,有sum[i]%n有n个结果,由抽屉原理可知必有两个余数相同,即sum【j]%n=sum[i]%n,则此两项sum【】相减的结果必为n的倍数,下标为j+1~i的数为所求结果。

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<cmath>
using namespace std;
const int maxn=1e4+100;
int n,a;
int num[maxn],mod[maxn];
int main()
{
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a);
        num[i]=num[i-1]+a;
    }
    //首先是求前缀和
    for(int i=1;i<=n;++i)
    {
        if(num[i]%n==0)
        {
            printf("%d\n",i);
            for(int j=1;j<=i;++j)
            {
                printf("%d\n",num[j]-num[j-1]);
            }
            break;
        }
        else if(mod[num[i]%n]!=0)
        {
            int j=mod[num[i]%n];
            printf("%d\n",i-j);
            for(j++;j<=i;++j)
            {
                printf("%d\n",num[j]-num[j-1]);
            }
            break;
        }
        //如果说上面的情况都没有存在的话
        mod[num[i]%n]=i;
    }
    return 0;
}

2:Halloween treats

Every year there is the same problem at Halloween: Each neighbour is only willing to give a certain total number of sweets on that day, no matter how many children call on him, so it may happen that a child will get nothing if it is too late. To avoid conflicts, the children have decided they will put all sweets together and then divide them evenly among themselves. From last year's experience of Halloween they know how many sweets they get from each neighbour. Since they care more about justice than about the number of sweets they get, they want to select a subset of the neighbours to visit, so that in sharing every child receives the same number of sweets. They will not be satisfied if they have any sweets left which cannot be divided.

Your job is to help the children and present a solution.

Input

The input contains several test cases.
The first line of each test case contains two integers c and n (1 ≤ c ≤ n ≤ 100000), the number of children and the number of neighbours, respectively. The next line contains n space separated integers a1 , ... , an (1 ≤ ai ≤ 100000 ), where ai represents the number of sweets the children get if they visit neighbour i.

The last test case is followed by two zeros.

Output

For each test case output one line with the indices of the neighbours the children should select (here, index i corresponds to neighbour i who gives a total number of ai sweets). If there is no solution where each child gets at least one sweet print "no sweets" instead. Note that if there are several solutions where each child gets at least one sweet, you may print any of them.

每年万圣节都有同样的问题:每个邻居只愿意在那天给一定数量的糖果,不管有多少孩子来找他,所以如果太晚了,孩子可能什么也得不到。为了避免冲突,孩子们决定把所有的糖果放在一起,然后平均分配给他们自己。从去年万圣节的经历中,他们知道每个邻居能给他们多少糖果。因为他们更关心的是公平,而不是他们得到的糖果的数量,所以他们想选择一个子集的邻居来拜访,这样在分享时,每个孩子都能得到同样数量的糖果。他们若有不能分的糖,就不满足。

你的工作是帮助孩子们并提出解决方案。

输入

输入包含几个测试用例。

每个测试用例的第一行分别包含两个整数c和n(1≤c≤n≤100000)、子代数和邻居数。下一行包含n空格分隔整数a1,…,an(1≤ai≤100000),其中ai表示孩子访问邻居i时得到的糖果数量。

最后一个测试用例后面跟着两个零。

输出

对于每个测试用例输出一行,其中包含孩子们应该选择的邻居的索引(这里,索引i对应于给出ai糖果总数的邻居i)。如果没有解决办法,每个孩子至少得到一个甜点打印“没有糖果”。注意,如果有几个解决方案,每个孩子至少得到一个甜点,你可以打印其中任何一个。

Sample Input

4 5
1 2 3 7 5
3 6
7 11 2 5 13 17
0 0

Sample Output

3 5
2 3 4

题意:

万圣节,有c个小孩,n家居民,i居民家有 ai 颗糖果,问小孩们要去哪几家要糖果,才能使他们能够平分要到的糖果,有多种情况可以输出任意一种。

题解:

输入x,y分别代表人数和邻居的数量,输入y个数,代表每个邻居所拥有的的糖的数量,对前缀和进行取余操作,记录取余后的数字对应的下标以及这个数出现的次数,如果说出现两次就说明当前区间内的数据的和是x的倍数,输出区间对应的下标,如果说在进行取余操作的过程中出现0,直接从最开始的下标输出,如果说所有的数据输入完毕还没有输出的话就输出“no sweets”。

#include<algorithm>
#include<iostream>
#include<string.h>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=1e5+100;
int a[maxn];
int indexxx[maxn];
int main()
{
    int x,y;
    while(~scanf("%d%d",&x,&y))
    {
        if(x+y==0) break;
        memset(indexxx,0,sizeof(indexxx));
        memset(a,0,sizeof(a));
        long long sum=0;
        int num;
        bool flag=true;
        for(int i=1; i<=y; ++i)
        {
            scanf("%d",&num);
            if(flag)
            {
                sum+=num;
                sum%=x;
                a[sum]++;
                if(a[sum]>=2)
                {
                    for(int j=indexxx[sum]+1;j<=i;++j)
                    {
                        printf("%d ",j);
                    }
                    printf("\n");
                    flag=false;
                }
                indexxx[sum]=i;
                if(sum==0)
                {
                    for(int j=1; j<=i; ++j)
                    {
                        printf("%d ",j);
                    }
                    printf("\n");
                    flag=false;
                }
            }
        }
        if(flag)
            printf("no sweets\n");

    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值