【题目大意】:给出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;
- }