【POJ 3420】Quad Tiling(dp|递推 +矩阵快速幂)
**
Quad Tiling
**
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4122 Accepted: 1885
Description
Tired of the Tri Tiling game finally, Michael turns to a more challengeable game, Quad Tiling:
In how many ways can you tile a 4 × N (1 ≤ N ≤ 109) rectangle with 2 × 1 dominoes? For the answer would be very big, output the answer modulo M (0 < M ≤ 105).
Input
Input consists of several test cases followed by a line containing double 0. Each test case consists of two integers, N and M, respectively.
Output
For each test case, output the answer modules M.
Sample Input
1 10000
3 10000
5 10000
0 0
Sample Output
1
11
95
Source
POJ Monthly–2007.10.06, Dagger
【题解】【递推+矩阵快速幂】
【刚开始,推式子ing….一段漫长而依赖std的时光】
【result : f[i]=f[i-1]+5*f[i-2]+f[i-3]-f[i-4]】
【具体这个式子是如何得来的?呵呵,我可不可以说我是凑的?!(我刚开始用f[1]、f[2]凑f[3],然后发现f[4]不满足,failed! 然后,用f[1]、f[2]、f[3]凑f[4],然后,f[5]不满足,failed!然后,我用前四个凑f[5],往后试了几个,发现accept!)】
【好了,朴素的算法已经得出,那么,构造矩阵即可】
初始矩阵为: {f[4],f[3],f[2],f[1]} => {36,11,5,1}
转移矩阵为:
【注意:转移矩阵在进行快速幂时,需要%m,但由于有负数需要+m%m】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
long long k[5][5];
}d;
int f[5],n,m,ans;
inline node jc(node a,node b)
{
node c;
memset(c.k,0,sizeof(c.k));
for(int i=1;i<=4;++i)
for(int j=1;j<=4;++j)
for(int l=1;l<=4;++l)
{
long long sm=a.k[i][l]*b.k[l][j];
sm=((sm+m)%m+m)%m;
c.k[i][j]=(c.k[i][j]+sm)%m;
}
return c;
}
node poww(node x,int p)
{
if(p==1) return d;
if(p%2==0)
{
node a=poww(x,p/2);
a=jc(a,a);
return a;
}
else
{
node a=poww(x,p/2);
a=jc(a,a);
a=jc(a,x);
return a;
}
}
inline int solve(int p)
{
node as=poww(d,p);
int sum[5];
memset(sum,0,sizeof(sum));
for(int i=1;i<=4;++i)
for(int j=1;j<=4;++j)
sum[j]=(sum[j]+as.k[i][j]*f[i]%m)%m;
return sum[1];
}
int main()
{
//freopen("int.txt","r",stdin);
//freopen("my.txt","w",stdout);
f[1]=36; f[2]=11; f[3]=5; f[4]=1;
d.k[1][1]=d.k[1][2]=d.k[2][3]=d.k[3][1]=d.k[3][4]=1;
d.k[2][1]=5; d.k[4][1]=-1;
while((scanf("%d%d",&n,&m)==2)&&!(n==0&&m==0))
{
if(n==1||n==2||n==3||n==4) {printf("%d\n",f[4-n+1]%m); continue;}
ans=solve(n-4);
printf("%d\n",ans);
}
}