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. 使用Curl进行抓取远程内容时url中文编码问题

    PHP中对于URL进行编码,可以使用 urlencode() 或者 rawurlencode(),二者的区别是前者把空格编码为 '+',而后者把空格编码为 '%20',不过应该注意的是,在编码时应该只 ...

  2. 如何得到动态链接库的输出函数tdump命令(225篇博文)

    有的时候,我们需要查看一个动态链接库的输出函数列表,有很多软件可以满足此要求,比如说 exeScope.不过,去下载一个软件总归是很麻烦,Delphi 本身就自带一个类似的工具,那就是 tdump.e ...

  3. 新的方法 (New Approach)¶

    第一章:简介 - ANSI Common Lisp 中文版 新的方法 (New Approach)¶ 本书的目标之一是不仅是教授 Lisp 语言,而是教授一种新的编程方法,这种方法因为有了 Lisp ...

  4. 100M 宽带办理

    http://zj.189.cn/zhuanti/kdsbz#%E5%8D%95%E5%AE%BD%E5%B8%A6%E7%89%B9%E6%83%A0

  5. 关于java中的事件类型

    java中的Date是为了证明:天才的程序员也会犯错: java中的Calendar是为了证明:普通的程序员也会犯错. ———————————————————— stackoverflow上大部分都推 ...

  6. Android UI布局TableLayout

    了解字面上TableLayout一个表格样式布局.这种布局将包括以行和列的形式的元件被布置.表格列的数目是列的各行中的最大数目.当然,表格里面的单元格它能够清空. 实例:LayoutDemo 执行效果 ...

  7. [Android学习笔记]jackson库的使用

    Jackson库一般用于序列化和反序列化操作,通常会涉及到的操作是: 1. Java Object -> Json String 2. Java Object -> Xml String ...

  8. HDU1176:免费馅饼(DP)

    Problem Description 都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼.说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁 ...

  9. HDU 1498 50 years, 50 colors(最小点覆盖,坑称号)

    50 years, 50 colors Problem Description On Octorber 21st, HDU 50-year-celebration, 50-color balloons ...

  10. Linux Shell脚本编程--curl命令详解

    用途说明 curl命令是一个功能强大的网络工具,它能够通过http.ftp等方式下载文件,也能够上传文件.其实curl远不止前面所说的那些功能,大家可以通过man curl阅读手册页获取更多的信息.类 ...