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;
}