【取火柴遊戲】
阿新 • • 發佈:2019-01-02
非常玄妙的博弈入門
好神仙的題啊
其實這就是經典的\(Nim\)問題
如果所有石子的異或和為\(0\),那麼這就是一個必敗狀態
這個我只會感性理解一下
首先所有的石子都是\(0\),異或和肯定是\(0\),這也自然是一個必敗狀態
而如果異或和不是\(0\),我們設異或和為\(X\)
我們可以找到這個\(X\)的最高位,顯然那些石子堆裡至少有一個這一位上也是\(1\)的,設這一個石子堆是\(x_i\)
那麼就有
\[x_1⊕x_2⊕x_3⊕...⊕x_i⊕...x_n=X\]
那麼顯然
\[x_1⊕x_2⊕x_3⊕...⊕x_i⊕...x_n⊕X=0\]
根據異或的結合律
\[x_1⊕x_2⊕...⊕(x_i⊕X)⊕...x_n=0\]
也就是說原來的\(x_i\)變成\(x_i⊕X\)就好了,也就是要取走\(x_i-x_i⊕X\),這樣就可以使得下一步變成必敗狀態
由於我們取走的一定得是正數,所以得滿足\(x_i-x_i⊕X>0\)
但是如果\(X=0\)的話,\(x_i⊕X=x_i\),所以\(x_i-x_i⊕X=0\),取走的是\(0\),並不滿足遊戲規則
所以一大波分析下來突然就覺得好有道理
程式碼
#include<iostream> #include<cstring> #include<cstdio> #define re register #define maxn 500005 #define lowbit(x) ((x)&(-x)) inline int read() { char c=getchar(); int x=0; while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar(); return x; } int n,a[maxn]; int ans,t; int main() { n=read(); for(re int i=1;i<=n;i++) a[i]=read(),ans^=a[i]; t=ans; if(!ans) { puts("lose"); return 0; } for(re int i=1;i<=n;i++) { if(a[i]-(a[i]^ans)>0) { printf("%d %d",a[i]-(a[i]^t),i); putchar(10); a[i]=(a[i]^t); break; } } for(re int i=1;i<=n;i++) printf("%d ",a[i]); return 0; }