[雅礼4-8]老魔杖 SG函数

又是SG函数打表找规律题,设1,2,3,4分别有a, b, c, d个。当(a+c)mod 2=(b+d)mod 3时先手必败。
别问我为什么,把每个转移列出来就能证了。。。
当然我考场上发现a mod 2,b mod 3,c mod 6,d mod 2后好像不影响答案,于是就那样写的。
代码:

type
  edge=^edgenode;
  edgenode=record
    t:longint;
    next:edge;
  end;
const
  n=14;
  maxn=10000;
var
  ca,tt,sa,sb,sc,sd,i,j,top,len1,len2,len3,len4:longint;
  s:ansistring;
  con,rev:array[1..maxn]of edge;
  sg,cd,st:array[1..maxn]of longint;
function q(a,b,c,d:longint):longint;
begin
  exit(d*2784+c*248+b*29+a);
end;
procedure ins(x,y:longint);
var
  p:edge;
begin
  inc(cd[x]);
  new(p);
  p^.t:=y;
  p^.next:=con[x];
  con[x]:=p;

  new(p);
  p^.t:=x;
  p^.next:=rev[y];
  rev[y]:=p;
end;


procedure build;
var
  a,b,c,d,o,i,j:longint;
  p:edge;
  app:array[0..9]of boolean;
begin
  for a:=0 to 28 do
    for b:=0 to 11 do
      for c:=0 to 7 do
        for d:=0 to 2 do
          if a+b*2+c*3+d*4<=28 then
          begin
            o:=q(a,b,c,d);
            if (a+1<=28)and(c+1<=7)and(d>0) then ins(o,q(a+1,b,c+1,d-1));
            if (b+2<=12)and(d>0) then ins(o,q(a,b+2,c,d-1));
            if (a+1<=28)and(b+1<=12)and(c>0) then ins(o,q(a+1,b+1,c-1,d));
            if (a+2<=28)and(b>0) then ins(o,q(a+2,b-1,c,d));
            if a>0 then ins(o,q(a-1,b,c,d));
            if b>1 then ins(o,q(a,b-2,c,d));
            if c>2 then ins(o,q(a,b,c-3,d));
            if d>3 then ins(o,q(a,b,c,d-4));
          end;
  top:=0;
  for i:=1 to maxn do
    if cd[i]=0 then
    begin
      inc(top);
      st[top]:=i;
    end;
  for i:=1 to maxn do
  begin

    fillchar(app,sizeof(app),false);
    o:=st[top];
    p:=con[o];
    while p<>nil do
    begin
      app[sg[p^.t]]:=true;
      p:=p^.next;
    end;
    for j:=0 to 9 do
      if app[j]=false then break;
    sg[o]:=j;

    dec(top);
    p:=rev[o];
    while p<>nil do
    begin
      dec(cd[p^.t]);
      if cd[p^.t]=0 then begin inc(top); st[top]:=p^.t; end;
      p:=p^.next;
    end;

  end;
end;
function getl(v:longint):longint;
begin
  while (v<=length(s))and((s[v]>='0')and(s[v]<='9')) do
    inc(v);
  exit(v-1);
end;
function getmod(l,r,md:longint):longint;
var
  i,m2,m3:longint;
begin
  m2:=ord(s[r]) mod 2;
  m3:=0;
  for i:=l to r do
    m3:=(m3+ord(s[i])) mod 3;
  if md=2 then exit(m2);
  if md=3 then exit(m3);
  if md=6 then
  begin
    if m3 mod 2=m2 then exit(m3)
    else exit(m3+3);
  end;
end;
begin  readln(ca);
  fillchar(cd,sizeof(cd),0);
  build;
  for tt:=1 to ca do
  begin
    readln(s);
    len1:=getl(1);
    sa:=getmod(1,len1,2);
    len2:=getl(len1+2);
    sb:=getmod(len1+2,len2,3);
    len3:=getl(len2+2);
    sc:=getmod(len2+2,len3,6);
    len4:=getl(len3+2);
    sd:=getmod(len3+2,len4,3);
    if sg[q(sa,sb,sc,sd)]=0 then writeln(0)
    else writeln(1);
  end;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值