1. 程式人生 > >[SDOI2009]E&D

[SDOI2009]E&D

組成 求助 表示 getch main std turn 題目 註意

題目描述

小E 與小W 進行一項名為“E&D”遊戲。

遊戲的規則如下: 桌子上有2n 堆石子,編號為1..2n。其中,為了方便起見,我們將第2k-1 堆與第2k 堆 (1 ≤ k ≤ n)視為同一組。第i堆的石子個數用一個正整數Si表示。 一次分割操作指的是,從桌子上任取一堆石子,將其移走。然後分割它同一組的另一堆 石子,從中取出若幹個石子放在被移走的位置,組成新的一堆。操作完成後,所有堆的石子 數必須保證大於0。顯然,被分割的一堆的石子數至少要為2。 兩個人輪流進行分割操作。如果輪到某人進行操作時,所有堆的石子數均為1,則此時 沒有石子可以操作,判此人輸掉比賽。

小E 進行第一次分割。他想知道,是否存在某種策 略使得他一定能戰勝小W。因此,他求助於小F,也就是你,請你告訴他是否存在必勝策略。 例如,假設初始時桌子上有4 堆石子,數量分別為1,2,3,1。小E可以選擇移走第1堆, 然後將第2堆分割(只能分出1 個石子)。接下來,小W 只能選擇移走第4 堆,然後將第3 堆分割為1 和2。最後輪到小E,他只能移走後兩堆中數量為1 的一堆,將另一堆分割為1 和1。這樣,輪到小W 時,所有堆的數量均為1,則他輸掉了比賽。故小E 存在必勝策略。

SOL:我們註意到對於每一堆,他們的決策是獨立的。所以求出所有堆得SG函數,再異或一下。

#include<bits/stdc++.h>
#define
gc getchar #define sight(c) (‘0‘<=c&&c<=‘9‘) using namespace std; int x,y,n,ans,T; inline void read(int &x){ static char c; for(c=gc();!sight(c);c=gc()); for(x=0;sight(c);c=gc()) x=x*10+c-48; } int sg(int x,int y){ long long tmp=2; for(int i=0;;i++,tmp*=2
) if( (x-1)%tmp<tmp/2 && (y-1)%tmp < tmp/2 ) return i; } int main () { read(T); while (T--) { ans=0; read(n); n>>=1; for (int i=1;i<=n;i++) read(x),read(y),ans^=sg(x,y); printf("%s\n",ans?"YES":"NO"); } return 0; }

[SDOI2009]E&D