您的位置:首页 > 其它

2016多校联合训练1 B题Chess (博弈论 SG函数)

2016-08-14 16:07 405 查看

      题目大意:一个n(n<=1000)行,20列的棋盘上有一些棋子,两个人下棋,每回合可以把任意一个棋子向右移动到这一行的离这个棋子最近的空格上(注意这里不一定是移动最后一个棋子),不能移动到棋盘外,不能移动了就算输,两个人都用最优策略,问先手是否有必胜策略。

      这题显然就是SG函数了吧。行与行之间互不影响,所以可以看成n个子游戏,求出它们各自的SG函数然后异或一下就可以了。我们发现只有20列,2^21=2097152,所以我们可以先把行的所有情况的SG函数预处理出来,然后每次询问O(1)就行了。

代码如下:

var
t,i,j,m,v,c,res,n,cl:longint;
cnt:array[0..22]of longint;
a:array[0..10000000]of longint;

procedure calc(x,c:longint);
begin
dec(x,1<<(c-1));inc(c);
while c<=20 do
begin
if x and (1<<(c-1))=0 then break;
inc(c);
end;
if c>20 then exit;
inc(x,1<<(c-1));
cnt[a[x]]:=1;
end;

procedure init;
begin
for i:=(1<<20)-1 downto 0 do
begin
fillchar(cnt,sizeof(cnt),0);
for j:=1 to 20 do
if i and (1<<(j-1))<>0 then calc(i,j);
for j:=0 to 20 do
if cnt[j]=0 then
begin
a[i]:=j;
break;
end;
end;
end;

procedure solve;
begin
readln(n);res:=0;
for i:=1 to n do
begin
c:=0;
read(m);
for j:=1 to m do
begin
read(v);
c:=c or(1<<(v-1));
end;
res:=res xor a[c];
end;
if res<>0 then writeln('YES')
else writeln('NO');
end;

begin
init;
readln(t);
while t>0 do
begin
dec(t);
solve;
end;
end.
View Code

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: