組合數學 HDU1808 鴿籠原理
太久沒寫題了菜的一匹。哭遼。
Halloween treats
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1383 Accepted Submission(s): 572
Special Judge
Problem Description
Every year there is the same problem at Halloween: Each neighbour is only willing to give a certain total number of sweets on that day, no matter how many children call on him, so it may happen that a child will get nothing if it is too late. To avoid conflicts, the children have decided they will put all sweets together and then divide them evenly among themselves. From last year's experience of Halloween they know how many sweets they get from each neighbour. Since they care more about justice than about the number of sweets they get, they want to select a subset of the neighbours to visit, so that in sharing every child receives the same number of sweets. They will not be satisfied if they have any sweets left which cannot be divided.
Your job is to help the children and present a solution.
Input
The input contains several test cases.
The first line of each test case contains two integers c and n (1 ≤ c ≤ n ≤ 100000), the number of children and the number of neighbours, respectively. The next line contains n space separated integers a1 , ... , an (1 ≤ ai ≤ 100000 ), where ai represents the number of sweets the children get if they visit neighbour i.
The last test case is followed by two zeros.
Output
For each test case output one line with the indices of the neighbours the children should select (here, index i corresponds to neighbour i who gives a total number of aisweets). If there is no solution where each child gets at least one sweet, print "no sweets" instead. Note that if there are several solutions where each child gets at least one sweet, you may print any of them.
Sample Input
4 5
1 2 3 7 5
3 6
7 11 2 5 13 17
0 0
Sample Output
3 5
2 3 4
鴿籠原理本身很簡單,所描述的就是一個可選數大於狀態數的問題,應用有趣又靈活。
例:
一位國際象棋大師有11周的時間備戰一場錦標賽,他決定每天至少下一盤棋,但是為了使自己不過分疲勞他還決定在每週不能下棋超過12盤。證明存在連續若干天,期間這位大師恰好下了21盤棋。
一共備戰11´7=77天。令x1,x2,…,x77分別為第1,2,…,77天下的棋數,則xi≥1(i=1,2,…,77)。我們構造如下嚴格遞增序列:
a1=x1, a2=x1+x2, a3=x1+x2+x3,…,a77=x1+x2+x3…+x77,其中,ai表示前i (i=1,2,…,77)天下棋的總數,並且1≤a1<a2<a3,…,<a77 ≤11´12=132 。
則序列a1+21, a2+21,a3+21,…,a77+21 也是一個嚴格遞增序列,並且22≤a1+21<a2+21<a3+21,…,<a77+21 ≤153 。
於是,這154個數:a1,a2,…,a77,a1+21,a2+21,…,a77+21中的每一個都是1到153中的一個整數。如果我們將這個序列中的每個元素作為物體,1到153中的每個數作為盒子,根據鴿巢原理,在這154中必有兩個元素相等,既然a1,a2,…,a77中沒有相等的元素,a1+21,a2+21,…,a77+21中也沒有相等的元素,則必然存在一個i和j(1≤i,j ≤77)使得aj=ai+21,從而這位國際象棋大師在第i+1,i+2,…,j天總共下了21盤棋。
對於這一道題呢,關鍵就是c<=n。
這種情況下,a[i]的字首和必定存在模c同餘的情況。
程式設計的時候注意考慮餘數為零的情況,與一開始的空狀態同餘。
我菜哭遼。
//鴿籠原理
//關鍵:c<=n
//所以a[i]的字首和一定有模c同餘的情況存在
//!
#include <cstdio>
#include <cstring>
const int maxn=1e5+10;
int main()
{
int c,n;
int a[maxn],flag[maxn];
long long sum;
while(~scanf("%d%d",&c,&n)){
if(!c&&!n) break;
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
sum=0;
memset(flag,-1,sizeof(flag));
flag[0]=0; //!注意特判0的情況,字首和同餘0,即輸出當前所有下標
for(int i=1;i<=n;++i){
sum+=a[i];
if(flag[sum%c]!=-1){
for(int j=flag[sum%c]+1;j<=i;++j){
printf("%d ",j);
}
printf("\n");
break;
}
flag[sum%c]=i;
}
}
return 0;
}