POJ 3420 Quad Tiling 状压DP+矩阵快速幂

链接:http://poj.org/problem?id=3420

题意:给一个4*N(1 ≤ N ≤ 1e9)的矩形空间,并且给不限块数的1*2的多米诺骨牌,问是由多少种方式能把这个矩形空间填满。

思路:看到这种问题果断想到状压,虽然是在看矩阵的时候看到的这道题。dp[i][j]表示在第i行状态为j的情况下的填满方式数,j的二进制表示中0表示对应位置上一行的骨牌是竖放,或者对应位置的骨牌是横放,1则表示该行该位置的骨牌是竖放。由于N最大1e9所以O(n)的DP绝对超时,用矩阵快速幂来加速DP递推。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <cstdlib>
#include <queue>
#include <stack>
#include <vector>
#include <ctype.h>
#include <algorithm>
#include <string>
#include <set>
#define PI acos(-1.0)
#define INF 0x7fffffff
#define eps 1e-8
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
#define maxn 20
#define maxm 20
using namespace std;
int a,MOD;
struct Matrix
{
    int n,m;
    LL a[maxn][maxm];
    void clear()
    {
        n=m=0;
        memset(a,0,sizeof(a));
    }
    Matrix operator +(const Matrix &b) const
    {
        Matrix tmp;
        tmp.n=n;
        tmp.m=m;
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
                tmp.a[i][j]=a[i][j]+b.a[i][j];
        return tmp;
    }
    Matrix operator -(const Matrix &b) const
    {
        Matrix tmp;
        tmp.n=n;
        tmp.m=m;
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
                tmp.a[i][j]=a[i][j]-b.a[i][j];
        return tmp;
    }
    Matrix operator *(const Matrix &b) const
    {
        Matrix tmp;
        tmp.clear();
        tmp.n=n;
        tmp.m=b.m;
        for(int i=0; i<n; i++)
            for(int j=0; j<b.m; j++)
                for(int k=0; k<m; k++)
                    tmp.a[i][j]=(tmp.a[i][j]+(a[i][k]*b.a[k][j])%MOD)%MOD;
        return tmp;
    }
};
Matrix M_quick_pow(Matrix &m,int k)
{
    Matrix tmp;
    tmp.n=m.n;
    tmp.m=m.m;
    for(int i=0; i<tmp.n; i++)
        for(int j=0; j<tmp.n; j++)
            if(i==j)
                tmp.a[i][j]=1;
            else tmp.a[i][j]=0;
    while(k)
    {
        if(k&1)
            tmp=tmp*m;
        k>>=1;
        m=m*m;
    }
    return tmp;
}
int flag (int i,int j)
{
    if(((i%3==0)&&(j%3==0)&&(i!=6)&&(j!=6))||((i==6)&&(j==9))||((i==9)&&(j==6)))
    {
        if((i&j)==0)
        return 1;
    }
    return 0;
}
int main()
{
    Matrix M,N,ans;
    while(scanf("%d%d",&a,&MOD)&&a&&MOD)
    {
        memset(N.a,0,sizeof(N.a));
        memset(M.a,0,sizeof(M.a));
        for(int i=0; i<16; i++)
        {
            for(int j=0; j<16; j++)
            {
                if(flag(i,j))
                    M.a[i][j]=1;
            }
        }
        M.m=M.n=16;
        ans=M_quick_pow(M,a);
        N.m=1;
        N.n=16;
        N.a[0][0]=1;
        ans=ans*N;
        printf("%lld\n",ans.a[0][0]%MOD);
    }
    return 0;
}
时间: 2024-10-14 19:48:04

POJ 3420 Quad Tiling 状压DP+矩阵快速幂的相关文章

poj 3420 Quad Tiling 状压dp

题意: 给4*n(n<10^9)的大矩形,问有多少种用1*2的小矩形填满的方案. 分析: 又是铺瓷砖,不过这次n太大,不能再一个一个格的dp了.可以先算出相邻两行的状态转移,再用矩阵来加速n行的状态转移. 代码: //poj 3420 //sep9 #include <iostream> using namespace std; const int maxN=16; struct MATRIX { __int64 m[maxN][maxN]; }mat; int n,mod; void

HDU 5434 Peace small elephant 状压dp+矩阵快速幂

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant Accepts: 38 Submissions: 108 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 小明很喜欢国际象棋,尤其喜欢国际象棋里面的大象(只要无阻挡能够斜着走任意格),但是他觉得国际象棋里的大象太凶残了,于是他

BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )

状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) --------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define b(x) (1 <&l

瓷砖铺放 (状压DP+矩阵快速幂)

未加矩阵快速幂 50分 1 const dx:array[1..8,1..3] of longint= 2 ((-1,0,0),(-1,0,0),(1,0,0),(0,1,0),(-1,0,0),(-1,1,0),(0,1,0),(-1,0,1)); 3 dy:array[1..8,1..3] of longint= 4 ((0,1,0),(0,-1,0),(0,-1,0),(1,0,0),(0,1,-1),(0,0,-1),(1,0,-1),(0,1,0)); 5 mo=65521; 6 va

POJ 3744 Scout YYF I (概率DP+矩阵快速幂)

题意:小明要从1走过一段直线雷区,给定n个地雷的坐标,他走一步的概率是p,两步的概率为1-p,问你他能安全通过雷区的概率. 析:很明显这是一个概率DP,用d(i)表示到达 i 时他安全的概率,那么d[i] = p * d[i-1] + (1-p) * d[i-2];这个状态转移方程很好理解, 就是说要想到达 i 要么从第 i-1 走一步,要么从 i-2 走两步,最后加起来,然后问题来了,这个数可能达到 1E8,那么时间空间复杂度都受不了, 观察这个状态转移方程,是不是很像Fibnacci数列,所

poj 2663 Tri Tiling 状压dp

题意: 给3*N(N<=30)的矩形,问有多少种用1*2的小矩形铺满的方案. 分析: 同poj2411. 代码: #include <iostream> using namespace std; __int64 ans[32][4]; int n,m; __int64 dp[2][1<<4]; __int64 solve() { int i,j,used; memset(dp,0,sizeof(dp)); __int64 *crt=dp[0],*nxt=dp[1]; crt[

POJ 3420 Quad Tiling 题解 《挑战程序设计竞赛》

POJ 3420 Quad Tiling贴瓷砖:4*N的地板上用2*1的瓷砖铺满,求所有方案数对M求余.3.4熟练掌握动态规划矩阵的幂久违地上了节课,太无聊,只好刷一题.假设S[n]表示填满n时的方案数,有S[0]=1.定义矩阵M[p][q] := 边缘p和边缘q可以拼合时取1,否则取0所谓的可以拼合表示,两个边缘拼起来后长度为1(为2就拼接不起来了),且内部缝隙可以用2*1的瓷砖填满.那么M就有一些简单的性质了,比如M的第一行应该是:0 0 0 0 0 0... 继续阅读:码农场 » POJ

POJ 1185 炮兵阵地 状压dp

http://poj.org/problem?id=1185 经典题目不必多说,直接贴代码. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n, m, cnt, size; 7 int a[110], st[70], ct[70]; 8 char str[15]; 9 int f[110][70][70]; 10 void init(

POJ3420 Quad Tiling DP + 矩阵快速幂

题目大意是用1*2的骨牌堆积成4*N的矩形,一共有多少种方法,N不超过10^9. 这题和曾经在庞果网上做过的一道木块砌墙几乎一样.因为骨牌我们可以横着放,竖着放,我们假设以4为列,N为行这样去看,并且在骨牌覆盖的位置上置1,所以一共最多有16种状态.我们在第M行放骨牌的时候,第M+1行的状态也是有可能被改变的,设S(i,j)表示某一行状态为i时,将其铺满后下一行状态为j的方案书.考虑下如果我们让矩阵S和S相乘会有什么意义,考虑一下会发现S*S的意义当某行状态为i,接着其后面第2行的状态为j的可行