poj 3370(抽屉原理)

【题目大意】:给出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...还要开输入挂才过!!!


[cpp]  view plain  copy
 print ?
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. #include <algorithm>  
  5. #include <vector>  
  6. #include <queue>  
  7. #include <cmath>  
  8. #include <string>  
  9. #include <cctype>  
  10. #include <map>  
  11. #include <iomanip>  
  12.                      
  13. using namespace std;  
  14.                      
  15. #define eps 1e-8  
  16. #define pi acos(-1.0)  
  17. #define inf 1<<30  
  18. #define pb push_back  
  19. #define lc(x) (x << 1)  
  20. #define rc(x) (x << 1 | 1)  
  21. #define lowbit(x) (x & (-x))  
  22. #define ll long long  
  23.   
  24. int a[100500];  
  25. int sum[100500],cnt[100500];  
  26. int n, c;  
  27.   
  28. int getint(){  
  29.     char c=getchar();  
  30.     int t=0;  
  31.     while (c<'0' || c>'9') {  
  32.         c=getchar();  
  33.     }  
  34.     while (c>='0' && c<='9') {  
  35.         t=t*10+c-'0';  
  36.         c=getchar();  
  37.     }  
  38.     return t;  
  39. }  
  40.   
  41. int main() {  
  42.     while(~scanf("%d%d",&c,&n)) {  
  43.         if(c==0 && n==0) break;  
  44.         sum[0]=0;  
  45.         int l,r;  
  46.         memset(cnt,-1,sizeof(cnt));  
  47.         for(int i=1; i<=n; i++) {  
  48.             a[i]=getint();  
  49.             sum[i]=(sum[i-1]+a[i])%c;  
  50.         }  
  51.         for (int i=1; i<=n; i++){  
  52.             if(cnt[sum[i]]==-1) cnt[sum[i]]=i;  
  53.             else {  
  54.                 l=cnt[sum[i]];  
  55.                 r=i;  
  56.                 break;  
  57.             }          
  58.         }  
  59.         if(cnt[0]!=-1){  
  60.             for(int i=1; i<=cnt[0]; i++)  
  61.                 printf("%d ",i);  
  62.             printf("\n");  
  63.         } else if(l!=-1) {  
  64.             for(int i=l+1; i<=r; i++)   
  65.                 printf("%d ",i);  
  66.             printf("\n");  
  67.         } else printf("no sweets\n");          
  68.     }  
  69.     return 0;  
  70. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值