http://hihocoder.com/contest/hiho42/problem/1

给定一个n,问我们3*n的矩阵有多少种覆盖的方法

第41周做的骨牌覆盖是2*n的,状态转移方程是dp[i] = dp[i-1] + dp[i-2],递推数列可以用矩阵快速幂来加速计算

我们可以用状态dp来做这一题,如果某个格子上被铺了骨牌,就标记为1,否则为0

那么每一列一共有8个状态。

两种状态的表示法

第一种:

dp[i][s] 表示填满第i行后,第i+1行的状态为s,

那么s的转移情况如下,

0->1,4,7

1->0,6

2->5

3->4

4->0,3

5->2

6->1

7->0

那么就可以构造出转换的矩阵

 int mat[][] = {
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , }
};

初始时,只有状态0存在,状态1,2,3,4,5,6,7都不存在

所以初始的向量为 A = [1,0,0,0,0,0,0,0,0]

转换n次后为,  A*mat^n

转化n次后,获得的是第i+1行的不同状态的个数,我们要的是第i+1行状态为0的个数,即A[0]

 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = << ;
const int MOD = ;
/* */
int mat[][] = {
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , }
};
int mat2[][] = {
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
};
struct Matrix
{
int mat[][];
Matrix()
{
memset(mat, , sizeof(mat));
}
};
Matrix operator*(const Matrix &lhs, const Matrix &rhs)
{
Matrix ret;//零矩阵
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
for (int k = ; k < ; ++k)
{
ret.mat[i][j] = (ret.mat[i][j] + lhs.mat[i][k] * rhs.mat[k][j]) % MOD;
}
}
} return ret;
}
Matrix operator^(Matrix a, int n)
{
Matrix ret;//单位矩阵
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
ret.mat[i][j] = mat2[i][j];
}
while (n)
{
if (n & )
{
ret = ret * a;
}
n >>= ;
a = a * a;
}
return ret;
} int main()
{
int n;
while (scanf("%d", &n) != EOF)
{ Matrix a;
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
a.mat[i][j] = mat[i][j];
}
a = a^n;
cout << a.mat[][] << endl; }
return ;
}

第二种转换方法为:

dp[i][s]表示填满第i-1行时,第i行的状态为s

同样的,可以得到转化的矩阵, 其实,两种转化的方法就是转化矩阵的不同

 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
const int MOD = ;
/* */
int mat[][] = {
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , }
};
int mat2[][] = {
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
{ , , , , , , , },
};
struct Matrix
{
int mat[][];
Matrix()
{
memset(mat, , sizeof(mat));
}
};
Matrix operator*(const Matrix &lhs, const Matrix &rhs)
{
Matrix ret;//零矩阵
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
for (int k = ; k < ; ++k)
{
ret.mat[i][j] = (ret.mat[i][j] + lhs.mat[i][k] * rhs.mat[k][j]) % MOD;
}
}
} return ret;
}
Matrix operator^(Matrix a, int n)
{
Matrix ret;//单位矩阵
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
ret.mat[i][j] = mat2[i][j];
}
while (n)
{
if (n & )
{
ret = ret * a;
}
n >>= ;
a = a * a;
}
return ret;
} int main()
{
int n;
while (scanf("%d", &n) != EOF)
{
n += ;
Matrix a;
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
a.mat[i][j] = mat[i][j];
}
a = a^n;
cout << a.mat[][] << endl; }
return ;
}

hihocoder第42周 3*N骨牌覆盖(状态dp+矩阵快速幂)的更多相关文章

  1. hihocoder第42周 k*N骨牌覆盖(状态dp+矩阵快速幂)

    上周的3*N的骨牌,因为状态只有8中,所以我们可以手算出状态转移的矩阵 但是这周是k*N,状态矩阵不好手算,都是我们改成用程序自动生成一个状态转移的矩阵就行了,然后用这个矩阵进行快速幂即可 枚举枚举上 ...

  2. 棋盘覆盖 状压DP+矩阵快速幂

    题意:有一个m 行n 列的矩形方格棋盘,1 < = m< = 5,1=< n< =10^9,用1*2 的骨牌(可横放或竖放)完全覆盖,骨牌不能重叠,有多少种不同的覆盖的方法.你 ...

  3. hihocoder第41周 骨牌覆盖(矩阵快速幂)

    由于棋盘只有两行,所以如果第i列的骨牌竖着放,那么就转移为第1列到第i-1列骨牌有多少种摆法 如果第一行第i列骨牌横着放,那么第二行第i列也要横着放,那么就转移为了第1列到第i-2列骨牌有多少种方法 ...

  4. hihoCoder 1143 : 骨牌覆盖问题·一(递推,矩阵快速幂)

    [题目链接]:click here~~ 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 骨牌,一种古老的玩具.今天我们要研究的是骨牌的覆盖问题: 我们有一个2xN的长条形 ...

  5. hihoCoder #1143 : 骨牌覆盖问题·一(矩阵乘法)

    1143 : 骨牌覆盖问题·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 骨牌,一种古老的玩具.今天我们要研究的是骨牌的覆盖问题: 我们有一个2xN的长条形棋盘,然 ...

  6. hihoCoder #1151 : 骨牌覆盖问题·二 (矩阵快速幂,DP)

    题意:给一个3*n的矩阵,要求用1*2的骨牌来填满,有多少种方案? 思路: 官网题解用的仍然是矩阵快速幂的方式.复杂度O(logn*83). 这样做需要构造一个23*23的矩阵,这个矩阵自乘n-1次, ...

  7. [HIHO1143]骨牌覆盖问题·一(矩阵快速幂,递推)

    题目链接:http://hihocoder.com/problemset/problem/1143 这个递推还是很经典的,结果是斐波那契数列.f(i) = f(i-1) + f(i-2).数据范围太大 ...

  8. hihoCoder #1162 : 骨牌覆盖问题·三 (矩阵快速幂,DP)

    题意:有一个k*n的棋盘,要求用1*2的骨牌来铺满,有多少种方案?(k<8,n<100000001) 思路: 由于k是比较小,但是又不那么小,可以专门构造这样的一个矩阵M,使得只要我们有一 ...

  9. hihoCoder#1743:K-偏差排列(矩阵快速幂+状压dp)

    题意 如果一个 \(1\to N\) 的排列 \(P=[P_1, P_2, ... P_N]\) 中的任意元素 \(P_i\) 都满足 \(|P_i-i| ≤ K\) ,我们就称 \(P\) 是 \( ...

随机推荐

  1. c++ inheritance -- 继承

    c++ inheritance -- 继承 终于要决心弄明白继承了,以前仅限于大学时学习,以后工作也没有用,现在就依照(百度百科)文章写些测试的代码. 文章说 ==================== ...

  2. 在toolbar里动态创建多个button(ext.net)

    private void setOneMenu() { string sql = "select id,name,gids from Config where name<>'高级 ...

  3. linux—select具体解释

    linux—select具体解释 select系统调用时用来让我们的程序监视多个文件句柄的状态变化的.程序会停在select这里等待,直到被监视的文件句柄有一个或多个发生了状态改变. 关于文件句柄,事 ...

  4. NET5

    ASP.NET5(RC1) - 翻译 前言 ASP.NET 5 是一次令人惊叹的对于ASP.NET的创新革命. 他将构建目标瞄准了 .NET Core CLR, 同时ASP.NET又是对于云服务进行优 ...

  5. Apache htaccess 重写假设文件存在!

    假设文件 data/cache/index.html 存在.那么才重写. 否则使用默认的MVC 重写.by default.fu@foxmail.com RewriteEngine on Rewrit ...

  6. 在Ubuntu Desktop打开终端的2种方式

    共有3中方法: 1.在Ubuntu左上角选择File/Open in Terminal 2.快捷键alt+F2调出Run a Command,输入gnome-terminal 添加右键支持 在终端,输 ...

  7. [Android学习笔记]使用ListView

    简单使用ListView 关键在于Adatper Adatper用来连接UI与数据源.Adapter既负责提供数据,又负责创建Item视图. 一般步骤: 1.创建list_item.xml,用来创建L ...

  8. [Xcode]some little skill

    Date:2014-1-2 Summary: 自己在使用Xcode的一些小习惯,记录下来,我是这么用的,你呢? Contents:1.使用#warning 在工作中,难免需要做一些test,但是又怕忘 ...

  9. JAVA NIO 选择器

    为什么要使用选择器 通道处于就绪状态后,就可以在缓冲区之间传送数据.可以采用非阻塞模式来检查通道是否就绪,但非阻塞模式还会做别的任务,当有多个通道同时存在时,很难将检查通道是否就绪与其他任务剥离开来, ...

  10. c#常见stream操作

    原文: c#常见stream操作 常见并常用的stream一共有 文件流(FileStream), 内存流(MemoryStream), 压缩流(GZipStream), 加密流(CrypToStre ...