求SG模板(附:HDU1848 &HDU1536)【pascal】

关于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=



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值