題意:David 玩一個石子游戲。遊戲中,有n堆石子,被編號爲0..n-1。兩名玩家輪流取石子。 每一輪遊戲,每名玩家選取3堆石子i,j,k(i<j,j<=k,且至少有一枚石子在第i堆石子中), 從i中取出一枚石子,並向j,k中各放入一枚石子(如果j=k則向k中放入2顆石子)。最 先不能取石子的人輸。 石子堆的個數不會超過23,每一堆石子不超過1000個。
解法:看上去是將石子都往右移,直到所有都到了n-1堆不能移爲止。首先是考慮每堆石子其實是獨立的一個子遊戲,堆與堆之間不相互影響。然後就是個數是偶數的對不會影響必勝必敗態,必敗態無法通過移動偶數堆得石子來扭轉局面,因爲必勝者只需對稱操作即可。所以每堆石子就成了01的狀態,sg值只是跟位置有關係了。預處理出每個位置的sg值即可。計算第一個可行步驟時候,暴力判斷ijk即可。
代碼:
/******************************************************
* @author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;
#define eps 1e-8
#define zero(_) (_<=eps)
const double pi=acos(-1.0);
typedef long long LL;
const int Max=100010;
const LL INF=0x3FFFFFFF;
int sg[100];
bool rem[100];
int n;
void init()
{
sg[0]=0;
for(int i=1; i<=25; i++)
{
memset(rem,0,sizeof rem);
for(int j=i-1; j>=0; j--)
for(int k=j; k>=0; k--)
{
rem[sg[j]^sg[k]]=1;
}
int t=0;
while(rem[t]) t++;
sg[i]=t;
}
}
bool help[100];
//0 1 2 4 7 8 11 13 14 16 19 21 22 25 26 28 31 32 35 37 38 41 42
int main()
{
init();
int kk=1;
while(cin>>n&&n)
{
memset(help,0,sizeof help);
int ans=0;
for(int i=0; i<n; i++)
{
int a;
scanf("%d",&a);
if(a)help[i]=1;
if(a&1)
{
ans^=sg[n-1-i];
}
}
printf("Game %d: ",kk++);
if(ans)
{
for(int i=0; i<n-1; i++)
{
if(help[i])
{
for(int j=i+1; j<n; j++)
for(int k=j; k<n; k++)
{
if((ans^sg[n-1-i]^sg[n-1-j]^sg[n-1-k])==0)
{
printf("%d %d %d\n",i,j,k);
goto end;
}
}
}
}
end:
;
}
else
puts("-1 -1 -1");
}
return 0;
}