2018.07.15【省赛模拟】模拟B组 【GDOI2016模拟3.11】游戏
#Description
#Input
#Output
#Sample Input
2 2
RL
LR
2 2
RR
RR
#Sample Output
LOSE
WIN
#Data Constraint
#题解
10%对于n=1,直接特判即可。
30%对于n,m<=3,可以用暴搜的方法跑过去。
60%对于另外的30%,打表“WIN”,别问我为什么。加上刚才的30分,即有60分。
好了,上面的东西太简单了,太肤浅了,我们来看看100分这么做。
首先,这是一道博弈论题废话
我们首先看看题意,发现:
L表示左上到右下一条都改成不活动的点(碰到不活动的点或边界截止)
R表示左下到右上一条都改成不活动的点(碰到不活动的点或边界截止)
X上面两个方向都改成不活动的点(碰到不活动的点或边界截止)
好的,就是这3种操作。
那么我们看看图:
我们发现,黑色格子上的操作不会影响白色格子,反之亦然。
那么我们就可以把原图分成两个棋局——
(注意:这两个图是拉直后的图而且灰色表示不存在的点)
这两个图中,三个操作也变了——
L表示上到下一条都改成不活动的点(碰到不活动的点或边界截止)
R表示左到右一条都改成不活动的点(碰到不活动的点或边界截止)
X上面两个方向都改成不活动的点(碰到不活动的点或边界截止)
然后呢,我们看看——由于每次选择一个操作,那么就会把当前的棋局分成2或4个独立的局面(看图)
然后,我们就可以用小的局面,推导到大的局面。
那么我们就可以设sg函数:
sg[sx,sy,ex,ey]表示以(sx,sy)和(ex,ey)为两个顶点的矩形中的mex值。
你问我sg函数是什么?
sg的定义:mex{sg[son1],sg[son2],……,sg[sonn]}
你问我sg定理是什么?
sg的定理:当,sg1sg2sg3……sgm>0时,先手胜,否则先手败。
证明?可以在“取石子游戏”这道题中,利用二进制来感性理解。
真正精确的证明我不会。
于是乎,我们就在一个大的局面中,枚举选择某个点之后,求出分成的2或4个小局面的sg值,把他们xor起来,然后,就可以把这个点的结果丢到大局面的sg的mex中,最后求一求mex,就可以得到大局面的sg值。
那么,我们可以利用递归的思想来做。
注意初始化和边界条件。
还有就是坑爹的栈和构图(构建新的图,要推好久)
标程:
var
i,j,k,l,n,m,maxm,maxn,p,q,maxx,maxy,now:longint;
map:array[1..20,1..20] of char;
op:array[1..20,1..20] of char;
sg:array[1..20,1..20,1..20,1..20] of longint;
first,second:longint;
function max(x,y:longint):longint;
begin
if x>y then exit(x);
exit(y);
end;
function dg(sx,sy,ex,ey:longint):longint;
var
i,j,k,l:longint;
jl:array[0..4] of longint;
p:array[0..400] of longint;
begin
p[0]:=0;
for i:=sx to ex do
begin
for j:=sy to ey do
begin
if op[i,j]<>' ' then
begin
if op[i,j]='L' then
begin
jl[0]:=2;
if j>sy then
begin
if sg[sx,sy,ex,j-1]<>-1 then
jl[1]:=sg[sx,sy,ex,j-1]
else
jl[1]:=dg(sx,sy,ex,j-1);
end
else
jl[1]:=0;
if j<ey then
begin
if sg[sx,j+1,ex,ey]<>-1 then
jl[2]:=sg[sx,j+1,ex,ey]
else
jl[2]:=dg(sx,j+1,ex,ey);
end
else
jl[2]:=0;
end
else
if op[i,j]='R' then
begin
jl[0]:=2;
if i>sx then
begin
if sg[sx,sy,i-1,ey]<>-1 then
jl[1]:=sg[sx,sy,i-1,ey]
else
jl[1]:=dg(sx,sy,i-1,ey);
end
else
jl[1]:=0;
if i<ex then
begin
if sg[i+1,sy,ex,ey]<>-1 then
jl[2]:=sg[i+1,sy,ex,ey]
else
jl[2]:=dg(i+1,sy,ex,ey);
end
else
jl[2]:=0;
end
else
if op[i,j]='X' then
begin
jl[0]:=4;
if (i>sx) and (j>sy) then
begin
if sg[sx,sy,i-1,j-1]<>-1 then
jl[1]:=sg[sx,sy,i-1,j-1]
else
jl[1]:=dg(sx,sy,i-1,j-1);
end
else
jl[1]:=0;
if (i>sx) and (j<ey) then
begin
if sg[sx,j+1,i-1,ey]<>-1 then
jl[2]:=sg[sx,j+1,i-1,ey]
else
jl[2]:=dg(sx,j+1,i-1,ey);
end
else
jl[2]:=0;
if (j>sy) and (i<ex) then
begin
if sg[i+1,sy,ex,j-1]<>-1 then
jl[3]:=sg[i+1,sy,ex,j-1]
else
jl[3]:=dg(i+1,sy,ex,j-1);
end
else
jl[3]:=0;
if (j<ey) and (i<ex) then
begin
if sg[i+1,j+1,ex,ey]<>-1 then
jl[4]:=sg[i+1,j+1,ex,ey]
else
jl[4]:=dg(i+1,j+1,ex,ey);
end
else
jl[4]:=0;
end;
inc(p[0]);
p[p[0]]:=jl[1];
for k:=2 to jl[0] do
begin
p[p[0]]:=jl[k] xor p[p[0]];
end;
p[p[0]]:=p[p[0]];
end;
end;
end;
for i:=1 to p[0] do
begin
for j:=i+1 to p[0] do
begin
if p[i]>p[j] then
begin
k:=p[i];
p[i]:=p[j];
p[j]:=k;
end;
end;
end;
j:=-1;
for i:=1 to p[0] do
begin
if p[i]=j+1 then
begin
j:=j+1;
end
else
if p[i]>j+1 then
begin
sg[sx,sy,ex,ey]:=j+1;
exit(j+1);
end;
end;
if p[0]=0 then
begin
sg[sx,sy,ex,ey]:=0;
exit(0);
end
else
begin
sg[sx,sy,ex,ey]:=p[p[0]]+1;
exit(p[p[0]]+1);
end;
end;
begin
while not eof do
begin
inc(now);
readln(n,m);
for i:=1 to n do
begin
for j:=1 to m do
begin
read(map[i,j]);
end;
readln;
end;
if (n=1) and (m=1) then
begin
writeln('WIN');
continue;
end;
for i:=1 to 20 do for j:=1 to 20 do op[i,j]:=' ';
maxn:=(n-1) div 2;
maxm:=(m-1) div 2;
p:=0;
maxy:=0;
for i:=1 to maxm+1 do
begin
p:=i;
q:=maxn+i;
j:=1;
k:=1+(i-1)*2;
while (j<=n) and (k<=m) do
begin
op[p,q]:=map[j,k];
maxy:=max(maxy,p);
inc(p);
inc(j);
inc(k);
end;
end;
maxx:=maxm+maxn+1;
p:=1;
for i:=1 to maxn do
begin
p:=i+1;
q:=maxn-i+1;
j:=i*2+1;
k:=1;
while (j<=n) and (k<=m) do
begin
op[p,q]:=map[j,k];
maxy:=max(maxy,p);
inc(p);
inc(j);
inc(k);
end;
end;
fillchar(sg,sizeof(sg),255);
for i:=1 to maxy do
begin
for j:=1 to maxx do
begin
if op[i,j]=' ' then
begin
sg[i,j,i,j]:=0;
end
else
begin
sg[i,j,i,j]:=1;
end;
end;
end;
if now=7 then
begin
now:=now;
end;
first:=dg(1,1,maxy,maxx);
for i:=1 to 20 do for j:=1 to 20 do op[i,j]:=' ';
maxn:=n div 2;
maxm:=m div 2;
p:=0;
maxy:=0;
for i:=1 to maxm do
begin
p:=i;
q:=maxn+i;
j:=1;
k:=i*2;
while (j<=n) and (k<=m) do
begin
op[p,q]:=map[j,k];
maxy:=max(maxy,p);
inc(p);
inc(j);
inc(k);
end;
end;
maxx:=maxm+maxn;
p:=0;
for i:=1 to maxn do
begin
p:=i;
q:=maxn-i+1;
j:=i*2;
k:=1;
while (j<=n) and (k<=m) do
begin
op[p,q]:=map[j,k];
maxy:=max(maxy,p);
inc(p);
inc(j);
inc(k);
end;
end;
fillchar(sg,sizeof(sg),255);
for i:=1 to maxy do
begin
for j:=1 to maxx do
begin
if op[i,j]=' ' then
begin
sg[i,j,i,j]:=0;
end
else
begin
sg[i,j,i,j]:=1;
end;
end;
end;
second:=dg(1,1,maxy,maxx);
if first xor second=0 then writeln('LOSE')
else writeln('WIN');
end;
end.