Submit: 1386 Solved: 840
[Submit][Status][Discuss]
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
4
1 0 1 5000
3
0 0 1
Sample Output
0 2 3
1
-1 -1 -1
0
1
-1 -1 -1
0
HINT
Source
又一道神題,一開始一直在分析最後一堆和倒數第二堆,分析出了一坨沒鳥用的性質
首先,我們按照套路,觀察有沒有模仿棋性質的操作,發現當豆子個數為偶數的時候後手可以把先手抵消掉
這樣的話豆子數實際就變成了一串01序列
我們此時回過頭來考慮拿豆子的操作,實際上就是一個multi-nim的模型,然後這題就可做了
因為處理的時候需要用到後面的SG函式,所以用記憶化搜尋
輸出方案的話。
暴力列舉第一個的位置,然後用異或的性質判斷一下
#include<cstdio> #include<cstring> const int MAXN=1001; inline char nc() { static char buf[MAXN*100],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN*100,stdin),p1==p2)?EOF:*p1++; } inline int read() { char c=nc();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=nc();} return x*f; } int N,S[MAXN],SG[MAXN];//遊戲可以看做是每個位置獨立進行的 int a[MAXN]; int dfs(int now) { if(SG[now]!=-1) return SG[now]; memset(S,0,sizeof(S)); for(int i=now+1;i<=N;i++) for(int j=i;j<=N;j++) S[ (dfs(i)^dfs(j)) ] = 1; for(int i=0;;i++) if(!S[i]) {SG[now]=i;break;} return SG[now]; } int main() { #ifdef WIN32 freopen("a.in","r",stdin); #else #endif int QwQ=read(); while(QwQ--) { memset(SG,-1,sizeof(SG)); N=read(); for(int i=1;i<=N;i++) a[i]=read(); for(int i=1;i<=N;i++) if(a[i]&1) dfs(i); int ans=0,tot=0; for(int i=1;i<=N;i++) if(a[i]&1)ans=(ans^dfs(i)); for(int i=1;i<=N;i++) for(int j=i+1;j<=N;j++) for(int k=j;k<=N;k++) { if( (ans^dfs(i)^dfs(j)^dfs(k) )!=0) continue; tot++; if(tot==1) printf("%d %d %d\n",i-1,j-1,k-1); } if(tot==0) printf("-1 -1 -1\n"); printf("%d\n",tot); } return 0; }