I and OI
Past...

题意很简单,用1*2的小矩形不重叠也不漏地铺满n*m的矩形,问方案数.

解法自然是状态压缩DP.

考虑每一行,用一个二进制串表示其状态,若第i位为1则表示在这一行的第i列竖放一个矩形,

它占用了这一行和下一行的第i列(下一行的第i列为0).其余的0表示横放的矩形.

具体做法:用f[i,j]表示第i行放置方法为j(j是二进制数)的方案数.

显然第一行的二进制串中不能出现连续的奇数个.

对于第i行的二进制串now,第i-1行的二进制串pre,它们应该满足now and pre=0,

且now or pre中也不能含连续奇数个0.

对于最后一行,只要上一行的二进制串中不含连续奇数个0即可.

code:

var   p:array[1..11,0..2500] of longint;
      f:array[1..11,0..2500] of int64;
      n,m:longint;

      function check(num,mm:longint):boolean;
      var   sum:longint;
      begin
            sum:=0;
            num:=num+1<<mm;
            while num>0 do
            begin
                  if num and 1=0 then inc(sum)
                  else if sum and 1=1 then exit(false)
                       else sum:=0;
                  num:=num>>1;
            end;
            if sum and 1=1 then exit(false)
            else exit(true);
      end;

      procedure prepare;
      var   O:longint;
      begin
            for M:=1 to 11 do
               for O:=0 to 1<<M-1 do
               if O=0 then
               begin
                     if M and 1=0 then inc(p[m,0])
               end
               else if check(O,M) then
               begin
                     inc(p[m,0]);
                     p[m,p[m,0]]:=o;
               end;
      end;

      function DP(n,m:longint):int64;
      var   i,j,k:longint;
            ans:int64;
      begin
            fillchar(f,sizeof(f),0);
            ans:=0;
            for i:=1 to p[m,0] do f[1,p[m,i]]:=1;
            for i:=2 to n-1 do
               for j:=0 to 1<<M-1 do
               if f[i-1,j]>0 then
                 for k:=0 to 1<<M-1 do
                 if (k and j=0)and(check(k or j,m)) then
                 f[i,k]:=int64(f[i,k])+int64(f[i-1,j]);

            for j:=0 to 1<<M-1 do
               if f[n-1,j]>0 then
                 if check(j,m) then
                 ans:=int64(ans)+int64(f[n-1,j]);
            exit(ans);
      end;

begin
      prepare;
      while not eof do
      begin
            readln(n,m);
            if n+m=0 then halt;
            if ((n and m) and 1)=1 then
              begin writeln(0); continue; end
            else if n=1 then
                   begin writeln(1); continue; end
                 else writeln(DP(n,m));
      end;
end.


 

类似的题目还有POJ1185,POJ3254.

posted on 2011-08-07 17:13  exponent  阅读(397)  评论(0编辑  收藏  举报