BZOJ 1188: [HNOI2007]分裂游戏(multi-nim)
生活随笔
收集整理的這篇文章主要介紹了
BZOJ 1188: [HNOI2007]分裂游戏(multi-nim)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Time Limit:?10 Sec??Memory Limit:?162 MB
Submit:?1386??Solved:?840
[Submit][Status][Discuss]
4
1 0 1 5000
3
0 0 1
1
-1 -1 -1
0
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] < = 10000Input
輸入文件第一行是一個整數t表示測試數據的組數, 接下來為t組測試數據(t<=10)。 每組測試數據的第一行是瓶子的個數n, 接下來的一行有n個由空格隔開的非負整數,表示每個瓶子中的豆子數。Output
對于每組測試數據,輸出包括兩行, 第一行為用一個空格兩兩隔開的三個整數,表示要想贏得游戲, 第一步應該選取的3個瓶子的編號i,j,k, 如果有多組符合要求的解,那么輸出字典序最小的一組。 如果無論如何都無法贏得游戲,那么輸出用一個空格兩兩隔開的三個-1。 第二行表示要想確保贏得比賽,第一步有多少種不同的取法。Sample Input
24
1 0 1 5000
3
0 0 1
Sample Output
0 2 31
-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 WIN32freopen("a.in","r",stdin);#else#endifint 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; }?
轉載于:https://www.cnblogs.com/zwfymqz/p/8469290.html
總結
以上是生活随笔為你收集整理的BZOJ 1188: [HNOI2007]分裂游戏(multi-nim)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: URL转义
- 下一篇: HDU 2047 阿牛的EOF牛肉串