poj3254

时间:2021-12-09 17:24:42

还是那句老话:dp关键在状态;

求有多少种排布方式,是任意两头牛不相邻(有些地方不能放);

不用心,一开始还纠结了半天

和之前USACO上某题方法是一样的,每一行放或不放只有两种情况

把它当作一个二进制数,转化为十进制作为状态则

到第i行第j种状态的方案数为

f[i,j]=sigma f[i-1,k] (j and k=0) 很飘逸的位运算解决了不相邻(可以想一想为什么);

code(代码比较丑陋 )

 const mo=;
var a,f:array[..,..] of longint;
    p,d:array[..] of longint;
    v:array[..] of boolean;
    s,n,m,i,j,k,x,y,t:longint;
    ans:int64;
    ff:boolean; function check(x:longint):boolean;
  begin
    s:=;
    fillchar(p,sizeof(p),);
    while x<> do
    begin
      inc(s);
      p[s]:=x mod ;
      if (p[s]=) then
      begin
        if v[s] then exit(false);
        if (p[s]=p[s-]) then exit(false);
      end;
      x:=x shr ;
    end;
    exit(true);
  end; begin
  readln(n,m);
  t:= shl m-;
  for i:= to n do
  begin
    fillchar(v,sizeof(v),false);
    for j:= to m do
    begin
      read(x);
      if x= then v[j]:=true;
    end;
    for j:= to t do
      if check(j) then
      begin
        inc(d[i]);
        a[i,d[i]]:=j;
      end;
    readln;
  end;
  for i:= to d[] do
    f[,i]:=;
  for i:= to n do
  begin
    for j:= to d[i] do
    begin
      x:=a[i,j];
      for k:= to d[i-] do
      begin
        y:=a[i-,k];
        if x and y= then
          f[i,j]:=(f[i,j]+f[i-,k]) mod mo;
      end;
    end;
  end;
  ans:=;
  for i:= to d[n] do
    ans:=(ans+f[n,i]) mod mo;
  writeln(ans mod mo);
end.