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