ACM-抽屉原理

抽屉原理有许多其它的名字,也有很多不同的描述,这里我就使用抽屉和着色去表示和描述这个定理。

简单形式的抽屉原理是显而易见的:如果使用n种颜色给n+1个物体着色,那么无论怎么做,都必定会有两个物体被着成相同的颜色。

但是,仅仅是简单形式的抽屉原理的具体应用也并不是其表面上看起来那么简单的,它注重的是一个分析和思考的过程,抽屉原理的内容仅仅充当这一过程中简单但不可或缺的一步。具体的应用可以参考《组合数学》鸽巢原理一章,大家就会发现抽屉原理的许多妙用,但是不容易想到。

其实,抽屉原理还有更复杂的形式,但是比较复杂,仅作扩展。


下面以一道题为例,进行分析,HDOJ:1808,题目如下:

Halloween treats

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 499    Accepted Submission(s): 161
Special Judge


Problem Description
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 a 1 , ... , a n (1 ≤ a i ≤ 100000 ), where a i 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 a i 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.
 

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个邻居家要糖果,现在已知每个邻居所能给的糖果数ai,问怎么个要法能保证全部所得的糖果能被c个孩子平分。
分析:
参考《组合数学》鸽巢原理一章中的应用3,我们考虑前k个邻居的糖果总数,那么这样的和一共有n个,a1,a1+a2,...,a1+...+an,如果将他们分别除以孩子的个数c,那么余数只可能在1~c-1之间,换句话说,和有n个,而余数有c-1个,并且从题目中可知c<=n,那么根据抽屉原理可知,必然有两个和的余数是相同的,这也就意味着这两个和中包含的公有项的和能被c整除,即为所求答案,详细推导见书上。
源代码:
#include <cstdio>
#include <cstring>

const int MAXN = 1e5+5;
int a[MAXN], SumMod[MAXN], flag[MAXN];

int main()
{
    int c, n;
    while(~scanf("%d%d", &c, &n) && (c+n))
    {
        SumMod[0] = 0;
        memset(flag, 0, sizeof(flag));
        for(int i=1; i<=n; ++i)
            scanf("%d", &a[i]);
        for(int i=1; i<=n; ++i)
        {
            SumMod[i] = (SumMod[i-1] + a[i]) % c;  // 处理前缀和,并取模
            if(flag[SumMod[i]] == 0)
                flag[SumMod[i]] = i;
            else                                   // 如果相同的余数在前面出现过
            {
                int j = flag[SumMod[i]] + 1;
                int k = j;
                for(; j<=i; ++j)                   // 公共项即为答案
                    if(j == k) printf("%d", j);
                    else printf(" %d", j);
                break;
            }
        }
        puts("");
    }
    return 0;
}

其他相关的题目还有,HDOJ:1205,3303。POJ:2356,3370。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ACM-ICPC(国际大学生程序设计竞赛)是一项面向大学生的计算机编程竞赛,涉及算法和数据结构等领域。在比赛中,选手需要解决一系列编程问题,使用合适的算法和数据结构来实现正确和高效的解决方案。 对于整理ACM-ICPC模板,以下是一些建议: 1. 了解比赛要求:首先,你需要了解ACM-ICPC比赛的具体要求和规则。这包括了解比赛所涉及的算法和数据结构,以及题目的类型和难度等。 2. 收集资料:收集与ACM-ICPC相关的资料,包括经典算法和数据结构的实现代码、常见问题的解题思路等。可以参考教材、博客、论文等资源。 3. 整理模板:将收集到的资料整理成模板。可以按照算法和数据结构的分类进行整理,例如排序算法、图算法、字符串算法等。对每个模板,添加必要的注释和示例代码,以便理解和使用。 4. 测试代码:对每个模板编写测试代码,确保它们的正确性和可靠性。可以使用已知的测试用例或自行设计测试用例。 5. 更新与扩充:定期更新和扩充模板,以适应ACM-ICPC比赛中新出现的算法和数据结构。同时,根据自己的经验和理解,对模板进行优化和改进。 6. 练习和复习:在比赛之前,利用整理好的模板进行练习和复习。尝试解决一些经典问题,使用模板中的算法和数据结构进行实现,并进行优化。 希望这些建议对你整理ACM-ICPC模板有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值