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 就是正确答案了!。
接下来讲第二种状态压缩的方法
很显然会有1<<4中状态
各个状态的匹配就达到了16*16 的矩阵。
矩阵的转移快速幂的意思就是1,2 3,4是同样的。``同理。
状态的转移 很巧妙的就是矩阵的相乘,
所以可以写出代码
接下来介绍两种思路:
先介绍一种 递推+矩阵的快速幂的方法
一种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); } }
所以可以写出代码
相关文章推荐
- POJ_3420_Quad Tiling_搜索,矩阵快速幂,状态压缩,动态规划
- poj 3420 Quad Tiling(状态压缩矩阵递推)
- POJ-3420 Quad Tiling 状态压缩+矩阵乘法
- POJ 3420 Quad Tiling 线性递推 矩阵快速幂
- POJ 3420 Quad Tiling (瓷砖问题+矩阵快速幂)
- 100道动态规划——31 POJ 2411 && POJ 2663 && POJ 3420 状态压缩 矩阵快速幂
- Quad Tiling POJ - 3420 矩阵快速幂
- Quad Tiling POJ - 3420 (矩阵快速幂)题解
- POJ - 3420 Quad Tiling (矩阵快速幂)
- POJ 3420 Quad Tiling(状压DP 用矩阵快速幂优化)
- poj 3420 Quad Tiling
- poj1185炮兵阵地 dp+状态压缩 经典题目
- poj2411 2663 2420 dp+状态压缩(多米诺骨牌问题)
- poj 3420 Quad Tiling 状压dp
- POJ 3420 Quad Tiling
- 【dp+数论】PKU-3420-Quad Tiling
- [POJ 3420] Quad Tiling
- poj 2440 DNA(状态压缩递推+矩阵)
- POJ3420 Quad Tiling
- poj 3420 Quad Tiling 【矩阵乘法】