hihocoder第42周 3*N骨牌覆盖(状态dp+矩阵快速幂)
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+矩阵快速幂)的更多相关文章
- hihocoder第42周 k*N骨牌覆盖(状态dp+矩阵快速幂)
上周的3*N的骨牌,因为状态只有8中,所以我们可以手算出状态转移的矩阵 但是这周是k*N,状态矩阵不好手算,都是我们改成用程序自动生成一个状态转移的矩阵就行了,然后用这个矩阵进行快速幂即可 枚举枚举上 ...
- 棋盘覆盖 状压DP+矩阵快速幂
题意:有一个m 行n 列的矩形方格棋盘,1 < = m< = 5,1=< n< =10^9,用1*2 的骨牌(可横放或竖放)完全覆盖,骨牌不能重叠,有多少种不同的覆盖的方法.你 ...
- hihocoder第41周 骨牌覆盖(矩阵快速幂)
由于棋盘只有两行,所以如果第i列的骨牌竖着放,那么就转移为第1列到第i-1列骨牌有多少种摆法 如果第一行第i列骨牌横着放,那么第二行第i列也要横着放,那么就转移为了第1列到第i-2列骨牌有多少种方法 ...
- hihoCoder 1143 : 骨牌覆盖问题·一(递推,矩阵快速幂)
[题目链接]:click here~~ 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 骨牌,一种古老的玩具.今天我们要研究的是骨牌的覆盖问题: 我们有一个2xN的长条形 ...
- hihoCoder #1143 : 骨牌覆盖问题·一(矩阵乘法)
1143 : 骨牌覆盖问题·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 骨牌,一种古老的玩具.今天我们要研究的是骨牌的覆盖问题: 我们有一个2xN的长条形棋盘,然 ...
- hihoCoder #1151 : 骨牌覆盖问题·二 (矩阵快速幂,DP)
题意:给一个3*n的矩阵,要求用1*2的骨牌来填满,有多少种方案? 思路: 官网题解用的仍然是矩阵快速幂的方式.复杂度O(logn*83). 这样做需要构造一个23*23的矩阵,这个矩阵自乘n-1次, ...
- [HIHO1143]骨牌覆盖问题·一(矩阵快速幂,递推)
题目链接:http://hihocoder.com/problemset/problem/1143 这个递推还是很经典的,结果是斐波那契数列.f(i) = f(i-1) + f(i-2).数据范围太大 ...
- hihoCoder #1162 : 骨牌覆盖问题·三 (矩阵快速幂,DP)
题意:有一个k*n的棋盘,要求用1*2的骨牌来铺满,有多少种方案?(k<8,n<100000001) 思路: 由于k是比较小,但是又不那么小,可以专门构造这样的一个矩阵M,使得只要我们有一 ...
- hihoCoder#1743:K-偏差排列(矩阵快速幂+状压dp)
题意 如果一个 \(1\to N\) 的排列 \(P=[P_1, P_2, ... P_N]\) 中的任意元素 \(P_i\) 都满足 \(|P_i-i| ≤ K\) ,我们就称 \(P\) 是 \( ...
随机推荐
- WebBrowser脚本错误的完美解决方案
原文:WebBrowser脚本错误的完美解决方案 当IE浏览器遇到脚本错误时浏览器,左下角会出现一个黄色图标,点击可以查看脚本错误的详细信息,并不会有弹出的错误信息框.当我们使用WebBrowse ...
- mysql union ,UNION RESULT
mysql> explain select * from t100 union all select * from t200; +----+--------------+------------ ...
- php网站共享session方法(相同一级域名)
这段时间做web开发使用的是php语言 要实现从主站进入子站时无需再登录(如已登录) 使用memcache实现 方法如下 修改php.ini如下 添加 extension=php_memcache.d ...
- MongoDB学习笔记(一)
MongoDB的介绍我就不说了.直接开始环境的搭建和连接.在这个之前,向大家介绍几个关于MongoDB的网站. 1. https://www.mongodb.com/ MongoDB的官网. 2. ...
- [C#基础] 继承
虚方法和覆写方法 虚方法可以使基类的引用访问"升至"派生类中 可以使用基类引用调用派生类的方法,只需满足下面的条件 派生类的方法和基类的方法有相同的签名和返回类型 基类的方法使用v ...
- 在Window和Linux下使用Zthread库
ZThread库是一个开源的跨平台高级面向对象的线性和sycnchronization 库,以运行POSIX 和Win32 系统中的C++程序. ZThread库的主页:http://zthread. ...
- 验证码 Captcha 之大插件
验证码 Captcha 之大插件小用 不知何年何月才能完成OADemo啊,总之还是一步一步来吧,这段时间开始着手了,先做登陆. 前段时间研究了一下在CentOS7下安装Mysql和Memcached ...
- ExtJS学习-----------Ext.Array,ExtJS对javascript中的Array的扩展
关于ExtJS对javascript中的Array的扩展.能够參考其帮助文档,文档下载地址:http://download.csdn.net/detail/z1137730824/7748893 因为 ...
- C语言里为何会有“2+2=5”的结果
写这篇原创文章是由于看到了极客中的一篇文章<有趣各种编程语言实现2+2=5>,当中C语言是这样实现的: int main() { char __func_version__[] = &qu ...
- 定义自己的布局RelativeLayout
绘制网格线
在Android画线必须由一个载体,无论是控制,无论是布局.实际上它们是从继承View.由画线的方式自己的控制或布局的定义是最常见的. 以下是在其定义中的小样本实现RelativeLayout绘制网络 ...