poj3370:http://poj.org/problem?id=3370
题意:给出两个数c和n,还有n个数,从n个数中找出任意一个组合,使得该组合数的和是c的倍数。
思想:抽屉原理(http://baike.baidu.com/view/8899.htm#5),创建c个抽屉,每个抽屉分别对应任意数除以c的余数(即模)0~c-1。从第一个组合数开始求和,分别对c求余。
比如
4 5
1 2 3 7 5
求和为1 3 6 13 18
和对c求余为1 3 2 1 2
当出现两个相同的数字时,就存在答案,答案为第一个重复数后面开始,到第二个重复数结束(3 2 1)。或者当出现的数字为0时,答案也存在。由于c<=n,c的余数有c个(包括0),n个和求余数的答案最少也有c个,所以必定存在0或者重复数。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct aa
{
int x;
int ind;
}res[100200];
int num[100200];
int check[100200];
int no[100200];
int cmp(const void *a,const void *b)
{
struct aa *c=(aa *)a,*d=(aa *)b;
if(c->x==d->x)
return c->ind-d->ind;
return c->x-d->x;
}
int main()
{
int i,j,n,c,t;
__int64 m;
while(scanf("%d%d",&c,&n)>0)
{
if(c==0&&n==0)
break;
memset(res,0,sizeof(res));
memset(check,0,sizeof(check));
memset(no,-1,sizeof(no));
for(i=1,m=0;i<=n;i++)
{
scanf("%d",&num[i]);
m+=num[i];
res[i].x=m%c;
res[i].ind=i;
}
for(i=1;i<=n;i++)
if(res[i].x==0)
{
for(j=1;j<=res[i].ind;j++)
printf("%d ",j);
printf("\n");
break;
}
else
if(check[res[i].x]==1)
{
for(j=no[res[i].x]+1;j<=res[i].ind;j++)
printf("%d ",j);
printf("\n");
break;
}
else
{check[res[i].x]=1;no[res[i].x]=i;}
}
return 0;
}