您的位置:首页 > 其它

POj 3420 Quad Tiling 状态压缩DP+递推+矩阵快速幂

2013-10-17 15:49 375 查看
哈哈,写了好久的,总算对了。

接下来介绍两种思路:

先介绍一种 递推+矩阵的快速幂的方法

一种DP的思想考虑4×n的最后一列 ,可以放的方法一共有5种

1.放4个 1×2 则 为dp[n-2]

2. 放2个 2x1 则为 dp[n-1]

3. 放 1x2 2x1 1x2 则为 dp[n-2]+dp[n-4]+.....+dp[0]

4. 放 1x2 1x2 2x1 为 dp[n-2]+dp[n-3]+dp[n-4]+....+dp[0]

5.和 4 一样 的另外一种情况 所以也是 dp[n-2]+dp[n-3]+....dp[0];

所以最后结果是 dp
=dp[n-1]+dp[n-2]+2*(dp[n-2]+dp[n-3]+..dp[0])+dp[n-2]+dp[n-4]+...dp[0];

然后写一个dp[n-2]=.....

减一下,化简 之后的结果是dp
=dp[n-1]+5*dp[n-2]+dp[n-3]-dp[n-4]; 这就是递推公式了

之后建立一个矩阵

( 1 5 1 -1

1 0 0 0

0 1 0 0

0 0 1 0 )

dp[0]=1,dp[1]=1,dp[2]=5,dp[3]=11 不断左乘那个矩阵 就可以转化为 那个矩阵的 幂,之后快速幂搞定!!

最后答案注意点,可能为负,那只要 (ans+m)%m 就是正确答案了!。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct matri
{
long long f[4][4];
};
long long n,m;
long long dp[5];
matri mul(matri a,matri b)
{
int i,j,k;
matri c;
memset(c.f,0,sizeof(c.f));
for(i=0;i<4;i++)
for(j=0;j<4;j++)
for(k=0;k<4;k++)
c.f[i][j]=(c.f[i][j]+a.f[i][k]*b.f[k][j])%m;
return c;
}
void eps_mul(matri a,int t)
{
matri s;
memset(s.f,0,sizeof(s.f));
s.f[0][0]=s.f[1][1]=s.f[2][2]=s.f[3][3]=1;
while(t){
if(t&1)
s=mul(s,a);
a=mul(a,a);
t=t>>1;
}
long long ans=0;
for(int i=0;i<4;i++)
ans=(ans+dp[i]*s.f[0][3-i]);
if((ans%=m)<0) ans=(ans+m)%m;
printf("%lld\n",ans);
}
int main()
{
dp[0]=1;dp[1]=1;dp[2]=5;dp[3]=11;
while(scanf("%lld%lld",&n,&m),n||m)
{
if(n<4) {
printf("%lld\n",dp
%m);
continue;
}
matri ss;
ss.f[0][0]=1;ss.f[0][1]=5;ss.f[0][2]=1;ss.f[0][3]=-1;
ss.f[1][0]=1;ss.f[1][1]=0;ss.f[1][2]=0;ss.f[1][3]=0;
ss.f[2][0]=0;ss.f[2][1]=1;ss.f[2][2]=0;ss.f[2][3]=0;
ss.f[3][0]=0;ss.f[3][1]=0;ss.f[3][2]=1;ss.f[3][3]=0;
eps_mul(ss,n-3);
}
}


接下来讲第二种状态压缩的方法

很显然会有1<<4中状态

各个状态的匹配就达到了16*16 的矩阵。

矩阵的转移快速幂的意思就是1,2 3,4是同样的。``同理。

状态的转移 很巧妙的就是矩阵的相乘,

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct matrix
{
int f[16][16];
};
int n,m;
int pre[16*16],now[16*16];
int top;
void dfs(int num,int p,int q)
{
if(num>4)return;
if(num==4)
{
pre[top]=q;
now[top++]=p;
return;
}
dfs(num+2,(p<<2)|3,(q<<2)|3);
dfs(num+1,(p<<1)|1,q<<1);
dfs(num+1,p<<1,(q<<1)|1);
}
matrix mul(matrix a,matrix b)
{
matrix s;
memset(s.f,0,sizeof(s.f));
int i,j,k;
for(i=0;i<16;i++)
for(j=0;j<16;j++)
for(k=0;k<16;k++)
s.f[i][j]=(s.f[i][j]+a.f[i][k]*b.f[k][j])%m;
return s;
}
void quick_pow(matrix A,int k)
{
int i;
matrix s;
memset(s.f,0,sizeof(s.f));
for(i=0;i<16;i++)
s.f[i][i]=1;
while(k){
if(k&1)
s=mul(s,A);
A=mul(A,A);
k=k>>1;
}
printf("%d\n",s.f[15][15]);
}
int main()
{
while(scanf("%d%d",&n,&m),n||m)
{
int i;
matrix s;
memset(s.f,0,sizeof(s.f));
top=0;
dfs(0,0,0);
for(i=0;i<top;i++)
s.f[pre[i]][now[i]]=1;
quick_pow(s,n);
}
}


所以可以写出代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: