poj 3420 Quad Tiling 状压dp+矩阵快速幂

题意:现有一个4*n的棋盘,问用2*1的多米诺骨牌将其完美覆盖的方法有多少种。

分析:这题首先想到的是状压dp,用f[i,j]表示前i-1列放满且第i列状态为j时的方案数。则f[i,j]=sum(f[i-1,k])。k为可转移到j的所有方案数。但是我们看到n有10^9那么大,所以肯定会TLE。但貌似也想不出其他更好的方法了,所以便只能优化当前的方法。这题用到的是矩阵优化。

首先对于每一个f[i]都可以看作一个1*16(或16*1)的矩阵,若f[i]能乘一个16*16的矩阵A后转移到f[i+1],我们则称矩阵A为状态转移矩阵。然后状态转移矩阵我们可以用一个暴力甚至是手动算出来。比如说状态0可以转移到状态15,则d[15,0]:=1.

然后用快速幂算出状态转移矩阵的n次幂再乘初始矩阵就好啦。

代码:

type
  arr=array[1..16,1..16] of int64;

var
  a:array[1..16] of int64;
  c,d:arr;
  n,m,i,j:longint;
  ans:int64;

procedure work(x,now,last:longint);
begin
  if x>5 then exit;
  if x>4 then
  begin
    d[now+1,last+1]:=1;
    exit;
  end;
  work(x+1,now shl 1+1,last shl 1);
  work(x+2,now shl 2,last shl 2+3);
  work(x+2,now shl 2+3,last shl 2+3);
  work(x+1,now shl 1,last shl 1+1);
end;

procedure cheng(a,b:arr);
var
  i,j,k:longint;
begin
  fillchar(c,sizeof(c),0);
  for i:=1 to 16 do
    for j:=1 to 16 do
      for k:=1 to 16 do
        c[i,j]:=(a[i,k]*b[k,j]+c[i,j]) mod m;
end;

procedure ksm(x:longint);
begin
  if x=0 then exit;
  ksm(x div 2);
  cheng(c,c);
  if x mod 2=1 then cheng(d,c);
end;

begin
  work(1,0,0);
  a[1]:=1; a[4]:=1; a[7]:=1; a[13]:=1; a[16]:=1;
  readln(n,m);
  while n+m>0 do
  begin
    fillchar(c,sizeof(c),0);
    for i:=1 to 16 do
      c[i,i]:=1;
    ksm(n-1);
    ans:=0;
    for i:=1 to 16 do
      ans:=(ans+a[i]*c[i,16]) mod m;
    writeln(ans);
    readln(n,m);
  end;
end.


你可能感兴趣的:(poj 3420 Quad Tiling 状压dp+矩阵快速幂)