Description
聰聰和睿睿最近迷上了一款叫做分裂的遊戲。 該遊戲的規則試: 共有 n 個瓶子, 標號爲 0,1,2…..n-1, 第 i 個瓶子中裝有 p[i]顆巧克力豆,兩個人輪流取豆子,每一輪每人選擇 3 個瓶子。標號爲 i,j,k, 並要保證 i < j , j < = k 且第 i 個瓶子中至少要有 1 顆巧克力豆,隨後這個人從第 i 個瓶子中拿走一顆豆 子並在 j,k 中各放入一粒豆子(j 可能等於 k) 。如果輪到某人而他無法按規則取豆子,那麼他將輸 掉比賽。勝利者可以拿走所有的巧克力豆! 兩人最後決定由聰聰先取豆子,爲了能夠得到最終的巧克力豆,聰聰自然希望贏得比賽。他思考 了一下,發現在有的情況下,先拿的人一定有辦法取勝,但是他不知道對於其他情況是否有必勝 策略,更不知道第一步該如何取。他決定偷偷請教聰明的你,希望你能告訴他,在給定每個瓶子 中的最初豆子數後是否能讓自己得到所有巧克力豆,他還希望你告訴他第一步該如何取,並且爲 了必勝,第一步有多少種取法? 假定 1 < n < = 21,p[i] < = 10000
Input
輸入文件第一行是一個整數t表示測試數據的組數,接下來爲t組測試數據(t<=10)。每組測試數據的第一行是瓶子的個數n,接下來的一行有n個由空格隔開的非負整數,表示每個瓶子中的豆子數。
Output
對於每組測試數據,輸出包括兩行,第一行爲用一個空格兩兩隔開的三個整數,表示要想贏得遊戲,第一步應該選取的3個瓶子的編號i,j,k,如果有多組符合要求的解,那麼輸出字典序最小的一組。如果無論如何都無法贏得遊戲,那麼輸出用一個空格兩兩隔開的三個-1。第二行表示要想確保贏得比賽,第一步有多少種不同的取法。
Sample Input
2
4
1 0 1 5000
3
0 0 1
Sample Output
0 2 3
1
-1 -1 -1
0
Solution
RE一次(因爲數組開在了主函數裏面 剛知道這樣也會RE Orz)
WA一次(因爲in[ ]數組開小了)
因爲可以預處理,所以把0到n-1反過來,變成從序號大的地方往序號小的方向移動
首先明確每個巧克力之間豆相互獨立
而在i處拿走一個,可以在j,k處各加一個,所以此處後繼狀態的sg函數可以用sg[j]^sg[k]表示
然後枚舉√
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<cstdlib>
using namespace std;
int t,n,sg[25];
bool in[50];
int main()
{
sg[0]=0;
for(int i=1;i<=21;i++)
{
memset(in,0,sizeof(in));
for(int j=i-1;j>=0;j--)
for(int k=j;k>=0;k--)
{
in[sg[j]^sg[k]]=1;
}
int l=0;
while(in[l])l++;
sg[i]=l;
}
scanf("%d",&t);
while(t--)
{
int ans=0,p;
scanf("%d",&n);
for(int i=n-1;i>=0;i--)
{
scanf("%d",&p);
if(p&1)
ans^=sg[i];
}
int cnt=0;
if(!ans)printf("-1 -1 -1\n");
else
{
for(int i=n-1;i>=0;i--)
{
for(int j=i-1;j>=0;j--)
for(int k=j;k>=0;k--)
{
if(!(ans^sg[i]^sg[j]^sg[k]))
{
if(!cnt)
printf("%d %d %d\n",n-1-i,n-1-j,n-1-k);
cnt++;
}
}
}
}
printf("%d\n",cnt);
}
return 0;
}