poj 3370 Halloween treats(抽屉原理)

【题目大意】:给出n个数,叫你从中选出任意个数,使得这些数的和是c的倍数。


【解题思路】:下午这道题被拿去当了选拔赛的题目。做的时候总觉得貌似在哪里见过,然后再那里没事%c搞啊搞啊,越搞越觉得像抽屉原理。。。。。然后,没错,就是你了。。。抽屉原理。


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

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

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

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

整数问题:把所有整数按照除以某个自然数m的余数分为m类,叫做m的剩余类或同余类,用[0],[1],[2],…,[m-1]表示.每一个类含有无穷多个数,例如[1]中含有1,m+1,2m+1,3m+1,….在研究与整除有关的问题时,常用剩余类作为抽屉.根据抽屉原理,可以证明:任意n+1个自然数中,总有两个自然数的差是n的倍数。(证明:n+1个自然数被n整除余数至少有两个相等(抽屉原理),不妨记为m=a1*n+b n=a2*n+b,则m-n整除n)。


所以,对于这道题而言。c<=n的,我们求出数字的前n项和之后,对于每一个和%c,则有根据抽屉原理必有两个数的余数相等。也就是说一定有两个的和是相等的。也就是说,在这中间的数的和是可以被c整除的。。。。。。

下午做的时候,没想到这样O(n)在G++一直TLE...还要开输入挂才过!!!


【代码】:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>
                   
using namespace std;
                   
#define eps 1e-8
#define pi acos(-1.0)
#define inf 1<<30
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long

int a[100500];
int sum[100500],cnt[100500];
int n, c;

int getint(){
    char c=getchar();
    int t=0;
    while (c<'0' || c>'9') {
        c=getchar();
    }
    while (c>='0' && c<='9') {
        t=t*10+c-'0';
        c=getchar();
    }
    return t;
}

int main() {
    while(~scanf("%d%d",&c,&n)) {
        if(c==0 && n==0) break;
        sum[0]=0;
        int l,r;
        memset(cnt,-1,sizeof(cnt));
        for(int i=1; i<=n; i++) {
            a[i]=getint();
            sum[i]=(sum[i-1]+a[i])%c;
        }
        for (int i=1; i<=n; i++){
            if(cnt[sum[i]]==-1) cnt[sum[i]]=i;
            else {
                l=cnt[sum[i]];
                r=i;
                break;
            }        
        }
        if(cnt[0]!=-1){
            for(int i=1; i<=cnt[0]; i++)
                printf("%d ",i);
            printf("\n");
        } else if(l!=-1) {
            for(int i=l+1; i<=r; i++) 
                printf("%d ",i);
            printf("\n");
        } else printf("no sweets\n");        
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值