关于SG函数的理论知识以及理解,请见这里,目前我没有看见比这个说得更棒的=w=
这里只是用来贴模板的
首先定义mex(minimal excludant)运算,
这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。
例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
对于一个给定的有向无环图,定义关于图的每个顶点的Sprague-Grundy函数g如下:
g(x)=mex{ g(y) | y是x的后继 },这里的g(x)即sg[x]
(详情请见上面的”这里“)
计算从1-n范围内的SG值。
f[]需要从小到大排序
1.可选步数为1~m的连续整数,直接取模即可,sg(x) = x % (m+1);
2.可选步数为任意步,sg(x) = x;(其实nim博弈的做法不就是n堆任意步的游戏组合么=。=)
3.可选步数为一系列不连续的数,用getsg()计算
关于getsg一般有两种方法
一、SG打表(最坏O(n^2))
procedure getsg(n:longint);
var
i,j:longint;
begin
fillchar(sg,sizeof(sg),0);
for i:=1 to n do
begin
fillchar(b,sizeof(b),false);
for j:=1 to 16 do
if (f[j]<=i) then b[sg[i-f[j]]]:=true else break;
for j:=0 to n do
if not b[j] then break;
sg[i]:=j;
end;
end;<span style="color:#3366ff;">
</span>
例:HDU1848
var
f :array[0..20] of longint;
n,m,q :longint;
i :longint;
sg :array[0..1010] of longint;
b :array[0..1010] of boolean;
procedure getsg(n:longint);
var
i,j:longint;
begin
fillchar(sg,sizeof(sg),0);
for i:=1 to n do
begin
fillchar(b,sizeof(b),false);
for j:=1 to 16 do
if (f[j]<=i) then b[sg[i-f[j]]]:=true else break;
for j:=0 to n do
if not b[j] then break;
sg[i]:=j;
end;
end;
begin
f[1]:=1;f[2]:=1;
for i:=3 to 17 do f[i]:=f[i-1]+f[i-2];
getsg(1000);
read(n,m,q);
while ((n<>0) and (m<>0) and (q<>0)) do
begin
if ((sg[m] xor sg[n] xor sg[q])=0) then writeln('Nacci')
else writeln('Fibo');
read(n,m,q);
end;
end.
二、dfs_sg(记忆化搜索)
function dfs_sg(x:longint):longint;
var
j:longint;
b:array[0..10010] of boolean;
begin
if (sg[x]<>-1) then exit(sg[x]);
fillchar(b,sizeof(b),false);
for j:=1 to n do
if (f[j]<=x) then b[dfs_sg(x-f[j])]:=true else break;
for j:=0 to 10010 do
if not b[j] then break;
sg[x]:=j;
exit(sg[x]);
end;
例:HDU1536
这题打表法会TLE =。=
var
n,t,m,ans,x :longint;
f :array[0..110] of longint;
i,j :longint;
sg :array[0..10010] of longint;
procedure sort(l,r: longint);
var
i,j,x,y: longint;
begin
i:=l;
j:=r;
x:=f[(l+r) div 2];
repeat
while f[i]<x do inc(i);
while x<f[j] do dec(j);
if not(i>j) then
begin
y:=f[i];f[i]:=f[j];f[j]:=y;
inc(i);j:=j-1;
end;
until i>j;
if l<j then sort(l,j);
if i<r then sort(i,r);
end;
//
function dfs_sg(x:longint):longint;
var
j:longint;
b:array[0..10010] of boolean;
begin
if (sg[x]<>-1) then exit(sg[x]);
fillchar(b,sizeof(b),false);
for j:=1 to n do
if (f[j]<=x) then b[dfs_sg(x-f[j])]:=true else break;
for j:=0 to 10010 do
if not b[j] then break;
sg[x]:=j;
exit(sg[x]);
end;
begin
read(n);
while (n<>0) do
begin
fillchar(f,sizeof(f),0);
for i:=1 to 10010 do sg[i]:=-1;
sg[0]:=0;
for i:=1 to n do read(f[i]);
sort(1,n);
read(t);
for i:=1 to t do
begin
ans:=0;
read(m);
for j:=1 to m do
begin
read(x);
sg[x]:=dfs_sg(x);
ans:=ans xor sg[x];
end;
if (ans=0) then write('L') else write('W');
end;
writeln;
read(n);
end;
end.
——by Eirlys
转载请注明出处=w=