有N堆石子放在N级楼梯上,楼梯编号为0..N-1(最下面那个是0好了),每堆有a[n]个石子。两人轮流游戏,每次将任意堆中的任意个石子移动到它下面那一层楼梯上。直到所有石子都移动到0号(就是楼底),那个人就赢了。仍然是问必胜策略。
然后用昨天学到的方法整理一下:当石子全部在0号楼梯的状态时P-position;当石子全部在1上的(也可以在0 1上面都有)是N-position。当0,1,2均存在石子时,又是两种情况:①a[1]=a[2],则先手必败;②a[1]≠a[2],则先手可以通过移动多的使a[1]=a[2]则先手必胜。(这个跟昨天一样嘛。。。)
如果当前是N-position,那么一定是从奇数楼梯放入偶数楼梯中。那么对于奇数楼梯的状态有两种:①从偶数楼梯放到奇数楼梯;②从奇数楼梯放入偶数楼梯。
所以,保证先手取奇数楼梯中的石子,使得异或和为0,则可以最后取走1中的石子。
算法:将奇数楼层的状态异或,和为0则先手必败,否则先手必胜。
首先我们要证明为什么奇楼梯石子异或的NIM和为0,则先手必败。
定能把最后的石子从奇楼梯1上移到偶楼梯0上。所以先手必败。
上的石子移到偶楼梯0上。
梯异或和为0。
在a1,a2,a3,…an中一定可以找到ai使得ai'=ai xor k<ai。(上一篇这个我已经证明了)
证毕。
题目:POJ1704
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 3943 | Accepted: 977 |
Description
Input
Output
Sample Input
2 3 1 2 3 8 1 5 6 7 9 12 14 17
Sample Output
Bob will win Georgia will win
这个题很猥琐。我不是说它算法猥琐。我当时看到那个图之后直接就写了个Staircase Nim,连题都没看,然后交上去:WA了……
连续好几遍:继续WA
后来读了读题,发现惊天秘密啊!问题的关键:每个格子只能放一个棋子,而且给出的pn并不是棋子的个数,而是每个棋子的位置……
根据每个格子只能放一个棋子这个性质,我们可以把一个放有棋子的格子跟它之前的所有空格子合并成一个格子,像这样
(红色表示有棋子放置)
分组之后
为什么要这么分呢?因为,如果对手将一个棋子向前移动,那么你一定可以将后面的一个棋子向前移动相同的步数。所以,空格子的数量对于结果是没有影响的。
然后对于与处理之后的数据,我们直接按照Staircase Nimm来做就可以了。
那个……再插一句……此题因为数据经过我们的预处理,那么他不是一个简单的Nimm,格子的数量会影响我们的决策。
当有棋子的格子(n)数量为偶数时,经过分析,我们发现奇数行的决策对于结果不会产生影响,所以将偶数行异或。
反之,则把奇数行异或。
var p:array[1..10000]of longint; t,n,i,ans:longint; procedure quicksort(head,tail:longint); var i,j,x,t:longint; begin i:=head;j:=tail;x:=p[random(tail-head+1)+head]; repeat while p[i]<x do inc(i); while p[j]>x do dec(j); if i<=j then begin t:=p[i];p[i]:=p[j];p[j]:=t; inc(i);dec(j); end; until i>j; if i<tail then quicksort(i,tail); if j>head then quicksort(head,j); end; begin readln(t); while t>0 do begin dec(t); readln(n); for i:=1 to n do read(p[i]); quicksort(1,n); for i:=n downto 1 do p[i]:=p[i]-p[i-1]-1; ans:=p[1]; for i:=1 to n do if i mod 2=1 then ans:=ans xor p[i]; if ans=0 then writeln('Bob will win') else writeln('Georgia will win'); end; readln; end.