Poi2004 gra{经典}
题意:给定一个1*m的棋盘,现在上面有n个棋子,每次可以把一个棋子移到编号比它的编号大的第一个格子里面,谁把一个棋子移到了m中就获胜。
M<=10^9,n<=10^6。
相当经典的一道题啊。
S1:若a[n]=m-1,a[n-1]=m-2,……则只能移动他们,Ans=这样连续的个数。若此时ans>0,则输出。
S2:谁都不想把棋子移动到m-1去,因此若谁移动后所有棋子都在[m-n-1..m-2],则胜,而且最后的状态必然为这个。把m-1做为地板,把两个空格之间作为楼梯,
连续棋子数B作为石子数,放在他们右边第一个空格上,则成为经典问题。
staircase nim 经典组合游戏
游戏开始时有许多硬币任意分布在楼梯上,共n阶楼梯从地面由下向上编号为0到n。游戏者在每次操作时可以将楼梯j(1<=j<=n)上的任意多但至少一个硬币移动到楼梯j-1上。游戏者轮流操作,将最后一枚硬币移至地上的人获胜。
分析:
这个问题与nim游戏的区别在于移走的硬币不是被扔掉而是被放进了另一堆硬币之中,考虑能否将这一部分楼梯排除考虑范围。奇数号楼梯只能将硬币扔到偶数号楼梯之中,同样偶数号楼梯上的硬币也只会被扔上奇数号楼梯。只考虑奇数号楼梯nim,若偶数楼梯只作容器,那么游戏变为nim。当偶数号楼梯上的硬币可以将硬币移出时,我们是不是仍然可以用nim的方法判断必败状态?
将奇数台阶的硬币数nim和为0称作条件A,结束状态满足条件A;任何满足条件A的状态都到达不满足条件A的状态;任何不满足条件A的状态都可以到达满足条件A的状态(nim)。因此一个状态为必败状态当且仅当它满足条件A。
设该游戏Sg函数为奇数格棋子数的Xor和S。
优化:对于转化后连续的奇数个0等价于1个0,连续偶数个0等价于2个0。
可行策略:
奇数楼梯i:S xor b[i]<b[i]
偶数楼梯i:b[i-1]<S xor b[i-1]<=b[i-1]+b[i]
program xqz; const maxn=3000000; oo=1 shl 30; var i,j,k,m,n,tot,now,ans:longint; b,a:array[0..maxn] of longint; procedure new(k:longint); begin if odd(tot) then now:=now xor b[tot]; inc(tot,k); b[tot]:=1; end; procedure print(ans:longint); begin writeln(ans); close(input); close(output); halt; end; begin assign(input,'gra.in'); reset(input); assign(output,'gra.out'); rewrite(output); read(m,n); for i:=1 to n do read(a[i]); k:=m-1; a[n+1]:=m-1; while a[n]=k do begin dec(n); dec(k); inc(ans); end; if ans>0 then print(ans); for i:=n downto 1 do if a[i+1]-a[i]=1 then inc(b[tot]) else if a[i+1]-a[i]=2 then new(1) else if odd(a[i+1]-a[i]) then new(2) else new(3); if odd(tot) then now:=now xor b[tot]; if now=0 then ans:=0 else for i:=1 to tot do if odd(i)and(now xor b[i]<b[i]) or not odd(i)and(b[i-1]<now xor b[i-1])and(b[i-1]+b[i]>=now xor b[i-1]) then inc(ans); writeln(ans); close(input); close(output); end.