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

来源:互联网 发布:nginx bind to failed 编辑:程序博客网 时间:2024/05/31 06:21

题意:现有一个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.


0 0
原创粉丝点击