POJ 3420 Quad Tiling
2016-04-20 20:12
363 查看
题目链接:http://poj.org/problem?id=3420
题意:用1×2的砖铺满4×n的矩形,问一共有多少种铺法。
思路:状态压缩DP, 只有两种铺法,横着铺和竖着铺。我们按行dp,那么就要把每一行的状态表示出来。对于横着铺,可以用两个相邻的1来表示;对于竖着放,我们将上面那行的位置记0,下面那行的位置记1,也就是竖着的0 1表示。先确定第一行的状态(按照状态规定,第一行的1都是横着放得来的)所以如果存在相邻的1,它们的数量必定是偶数个。接着我们枚举相邻两行的状态进行转移,当前行s1,上一行s2:s1放完的时候s2应该也被填充满了,所以(s1 | s2) 一定是满的。其次再考虑两行的兼容问题,(s1 & s2)为第一行的可行状态时才兼容,因为所有竖着放的位置会被忽略(1
& 0),只剩下横着放的位置。但是数据范围很大,我们就用矩阵快速幂来解决。构造一个16*16的矩阵,(i,j)表示上一行状态为i时,当前状态为j时是否能转移。
题意:用1×2的砖铺满4×n的矩形,问一共有多少种铺法。
思路:状态压缩DP, 只有两种铺法,横着铺和竖着铺。我们按行dp,那么就要把每一行的状态表示出来。对于横着铺,可以用两个相邻的1来表示;对于竖着放,我们将上面那行的位置记0,下面那行的位置记1,也就是竖着的0 1表示。先确定第一行的状态(按照状态规定,第一行的1都是横着放得来的)所以如果存在相邻的1,它们的数量必定是偶数个。接着我们枚举相邻两行的状态进行转移,当前行s1,上一行s2:s1放完的时候s2应该也被填充满了,所以(s1 | s2) 一定是满的。其次再考虑两行的兼容问题,(s1 & s2)为第一行的可行状态时才兼容,因为所有竖着放的位置会被忽略(1
& 0),只剩下横着放的位置。但是数据范围很大,我们就用矩阵快速幂来解决。构造一个16*16的矩阵,(i,j)表示上一行状态为i时,当前状态为j时是否能转移。
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <cstdlib> #include <iostream> #include <algorithm> #include <stack> #include <map> #include <set> #include <vector> #include <sstream> #include <queue> #include <utility> using namespace std; #define rep(i,j,k) for (int i=j;i<=k;i++) #define Rrep(i,j,k) for (int i=j;i>=k;i--) #define Clean(x,y) memset(x,y,sizeof(x)) #define LL long long #define ULL unsigned long long #define inf 0x7fffffff #define mod %100000007 int n,m; bool can[16]; LL ans[16]; struct node { int a[16][16]; }x; bool check(int state) { int x = 0; while( state ) { if ( state & 1 ) x++; else { if ( x & 1 ) return false; x = 0; } state>>=1; } return !(x & 1); } bool fit(int x1 , int x2 , int uplim) { if ( (x1 | x2) != uplim ) return false; int t = x1 & x2; return can[t]; } void init() { Clean(can,false); rep(i,0,15) if ( check(i) ) can[i] = true; rep(i,0,15) if ( can[i] ) ans[i] = 1; Clean(x.a,0); rep(i,0,15) rep(j,0,15) if ( fit(i,j,15) ) ++x.a[i][j]; } node multi(node a , node b) { node temp; Clean(temp.a,0); rep(i,0,15) rep(j,0,15) rep(k,0,15) temp.a[i][j] = ( temp.a[i][j] + a.a[i][k] * b.a[k][j] )% m; return temp; } int main() { init(); while( scanf("%d%d",&n,&m) == 2 ) { if ( m + n == 0 ) break; int b = n-1; Clean(x.a,0); rep(i,0,15) rep(j,0,15) if ( fit(i,j,15) ) ++x.a[i][j]; node temp = x; node y; Clean(y.a,0); rep(i,0,15) y.a[i][i] = 1; //单位矩阵 while( b ) { if ( b & 1 ) y = multi(y,temp); temp = multi(temp,temp); b>>=1; } int s = 0; rep(i,0,15) s = ( s + ans[i] * y.a[15][i] )% m; printf("%d\n",s); } return 0; }
相关文章推荐
- android的消息处理机制(图+源码分析)——Looper,Handler,Message
- sublime中使用python3(windows环境)
- python中的转义字符
- 查看关于yum的配置
- Java反射实现接口
- intent传递有没有大小限制,是多少?
- (C#)WinForm窗体间传值
- CSRF 批量进行校验
- LeetCode-342. Power of Four
- 插入排序法
- Codeforces Beta Round #29 (Div. 2, Codeforces format) C. Mail Stamps 拓扑排序
- PHP 函数获取文件名
- 27. Remove Element
- Java NIO写事件处理技巧
- 工资
- Spring框架AOP的配置和实现的简单例子
- Bzoj3473:字符串:广义后缀自动机
- struts2中的Action接收表单传递过来的参数
- PHP算法排序
- 特邀美国EMC实战专家Mark来华授课