首页 > 代码库 > poj 3370 Halloween treats

poj 3370 Halloween treats

这题用抽屉原理写起来真的很简单,从中也明白数学的重要性。

几个抽屉原理如下:

原理1 把多于n个的物体放到n个抽屉里,则至少有一个抽屉里的东西不少于两件;

原理2 把多于mn(m乘以n)个的物体放到n个抽屉里,则至少有一个抽屉里有不少于m+1的物体。

原理3 把无穷多件物体放入n个抽屉,则至少有一个抽屉里 有无穷个物体。.

原理 4 把(mn-1)个物体放入n个抽屉中,其中必有一个抽屉中至多有(m—1)个物体。


这题的题意很简单,就是求出哪些数加起来能够被某个数整除。我们知道一个整数n有n个同余类,这n个同余类就可以看做n个抽屉,而题目中给出c<=n,再加上0,那么就有n+1个数,大于c,由原理1可以知道一定存在这样的整数,满足题意。因为至少有两个数的余数相同,那么两者相减之后一定能被c整除。

因此我们可以用一个mod[i]数组来记录从0到i所有整数的和%c的值,这样,当mod[i]=0或者mod[i]=a之前出现过,那么就可以得出,从之前出现的那个数开始的下一个数到i为止的数加起来一定能被c整除,例如:如果mod[2]=1,并且mod[5]=1,那么从3到5这三个数加起来一定能够被c整除。

#include<cstdio>
#include<cstring>
const int N=100005;
int sweet[N],mod[N];
bool isok[N];
int main()
{
    int c,n;
    while(scanf("%d%d",&c,&n))
    {
        if(c==0&&n==0)
            break;
        memset(isok,false,sizeof(isok));
        sweet[0]=0,mod[0]=0;
        long long sum=0;//这里要注意,不能用int。
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&sweet[i]);
            sum+=sweet[i];
            mod[i]=sum%c;
        }
        int start=0;
        for(int i=n;i>=0;i--)
        {
            if(isok[mod[i]])
            {
                start=i;
                break;
            }
            isok[mod[i]]=true;
        }
        //printf("start=%d\n",start);
        int e=start+1;
        while(true)
        {
            printf("%d ",e);
            e++;
            if(mod[start]==mod[e])
                break;
        }
        printf("%d\n",e);
    }
    return 0;
}


poj 3370 Halloween treats