NC17890 方格填色
题目
题目描述
给一个m x n的方格,Applese想要给方格填上颜色,每个格子可以是黑色或者白色。他要求左右相邻两格不能同为白色且相邻两列不能全为黑色。
求满足条件的方案数。
输入描述
输入两个整数m, n。\((1 ≤ m ≤ 5, 1 ≤ n ≤ 10^{18})\)。
输出描述
输出答案对 \(10^9 + 7\) 取模的结果。
**示例1 **
输入
3 1
输出
8
示例2
输入
3 5
输出
1640
示例3
输入
5 5
输出
351032
题解
知识点:状压dp,运算优化。
注意到可以一列一列摆,设 \(0\) 代表黑色,\(1\) 代表白色,这样比反过来方便。设第 \(i\) 列状态为 \(st1\) ,第 \(i-1\) 列状态为 \(st2\) ,于是首先 \(st1\) 和 \(st2\) 自己都要满足 st & (st<<1) 不能为 \(1\) ,即相邻不为白色,随后 st1 & st2 必须大于 \(0\) ,即两列不能都为黑色。设 \(dp[i][st]\) 表示摆到第 \(i\) 列,状态 \(st\) 时的方案数,有转移方程:
\]
注意到 \(n\) 十分的大,考虑优化。发现转移方程只和这一列的 \(st1\) 和上一列的 \(st2\) 有关,并且对于一组 \((st1,st2)\) 能否转移是不随 \(i\) 变化的,因此我们可以预先确定每一组 \((st1,st2)\) 是否可以从 \(st2\) 转移到 \(st1\)。显然,用矩阵快速幂,可以解决这个问题了。假设 $f(i,j) $ ,表示状态 \((i,j)\) 是否可以转移,用 \(01\) 表示,于是 \(f(i,j) = !(i \& j) \and (i | j)\)。矩阵构造如下:
\begin{array}{c}
dp[n][0]\\
dp[n][1]\\
\vdots\\
dp[n][2^m-1]
\end{array}
\right)
=
\left (
\begin{array}{c}
f(0,0) & f(1,0) & \cdots & f(2^m-1,0)\\
f(0,1) & f(1,1) & \cdots & f(2^m-1,1)\\
\vdots & \vdots & \ddots & \vdots\\
f(0,2^m-1) & f(1,2^m-1) & \cdots & f(2^m-1,2^m-1)
\end{array}
\right)
^{n-1}
\left (
\begin{array}{c}
dp[1][0]\\
dp[1][1]\\
\vdots\\
dp[1][2^m-1]
\end{array}
\right)
\]
时间复杂度 \(O(8^m \log n)\)
空间复杂度 \(O(4^m)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9 + 7;
///矩阵快速幂取余,O(n^3logk)
struct Matrix {
int n, m;//不能const,快速幂要复制
vector<vector<ll>> mat;
explicit Matrix(int _n) :n(_n), m(_n), mat(_n + 1, vector<ll>(_n + 1)) {
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
mat[i][j] = i == j;
}//初始化n阶单位矩阵,explicit防止误用类型转换
Matrix(int _n, int _m) :n(_n), m(_m), mat(_n + 1, vector<ll>(_m + 1)) {}//初始化nxm零矩阵
friend Matrix operator*(const Matrix &A, const Matrix &B) {
Matrix ans(A.n, B.m);
if (A.m != B.n) return ans;
for (int i = 1;i <= A.n;i++)
for (int j = 1;j <= B.m;j++)
for (int k = 1;k <= A.m;k++) //a.m == b.n
ans.mat[i][j] = (ans.mat[i][j] + A.mat[i][k] * B.mat[k][j]) % mod;
return ans;
}//矩阵乘法取余
friend Matrix operator^(Matrix A, ll k) {
Matrix ans(A.n);//A必须是方阵
while (k) {
if (k & 1) ans = ans * A;
k >>= 1;
A = A * A;
}
return ans;
}//快速幂取余
void output() const {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
cout << mat[i][j] << ' ';
cout << '\n';
}
cout << '\n';
}//输出检测
};
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll m, n;
cin >> m >> n;
Matrix init(1 << m, 1);
for (int i = 1;i <= (1 << m);i++)
init.mat[i][1] = 1;
Matrix feat(1 << m, 1 << m);
for (int i = 0;i < (1 << m);i++)
for (int j = 0;j < (1 << m);j++)
feat.mat[i + 1][j + 1] = !(i & j) && (i | j);
Matrix res = (feat ^ (n - 1)) * init;
int ans = 0;
for (int i = 1;i <= (1 << m);i++) ans = (ans + res.mat[i][1]) % mod;
cout << ans << '\n';
return 0;
}
NC17890 方格填色的更多相关文章
- java算法 蓝桥杯(题+答案) 方格填数
6.方格填数 (结果填空) 如下的10个格子 (如果显示有问题,也可以参看[图1.jpg]) 填入0~9的数字.要求:连续的两个数字不能相邻.(左右.上下.对角都算相邻) 一共有多少种可能的填数方案 ...
- 蓝桥杯比赛javaB组练习《方格填数》
方格填数 如下的10个格子 +--+--+--+ | | | |+--+--+--+--+| | | | |+--+--+--+--+| | | |+--+--+--+ ( ...
- java算法 第七届 蓝桥杯B组(题+答案) 6.方格填数
6.方格填数 (结果填空) 如下的10个格子 (如果显示有问题,也可以参看[图1.jpg]) 填入0~9的数字.要求:连续的两个数字不能相邻.(左右.上下.对角都算相邻) 一共有多少种可能的填数方案 ...
- 1002: 当不成勇者的Water只好去下棋了---课程作业---图的填色
1002: 当不成勇者的Water只好去下棋了 Time Limit: 1 Sec Memory Limit: 128 MB Description 由于魔王BOSS躲起来了,说好要当勇者的Wate ...
- c++_方格填数(最新方法)
方格填数 如下的10个格子 +--+--+--+ | | | |+--+--+--+--+| | | | |+--+--+--+--+| | | |+--+--+--+ (如果显示有问题,也可以参 ...
- 123457123457#0#----com.MC.konglongtianse222----前拼后广--恐龙填色mc-mc1111
com.MC.konglongtianse222----前拼后广--恐龙填色mc
- 123457123456#2#----com.MC.HuiHuaGame33--前拼后广--画画填色Game-mc
com.MC.HuiHuaGame33--前拼后广--画画填色Game-mc
- 123457123456#0#-----com.ppGame.huaHua65--前拼后广--儿童填色-pp
com.ppGame.huaHua65--前拼后广--儿童填色-pp
- 123457123456#0#-----com.twoapp.ErTongHuaHua01--前拼后广--儿童绘画填色游戏jiemei
com.twoapp.ErTongHuaHua01----儿童绘画填色游戏jiemei
- 第七届蓝桥杯试题c/c++A组方格填数 回溯法
方格填数如下的10个格子 +--+--+--+ | | | |+--+--+--+--+| | | | |+--+--+--+--+| | | |+--+--+--+(如果 ...
随机推荐
- docker容器中执行GPU环境中的tensorflow和pytorch任务
1. 背景 (1) 业务方提供了一台有GPU的服务器,且已经安装了显卡等组件,cuda版本10.2,具体信息如下 (2) 在裸机上部署anaconda.pytorch.tensorflow较为麻烦,因 ...
- 【MicroPython】用 c 添加接口 -- 框架介绍
[来源]https://www.eemaker.com/micropython-c-kuangjia.html
- js jquery - 获取元素(父节点,子节点,兄弟节点),元素筛选 (转载)
一 , js 获取元素(父节点,子节点,兄弟节点) var test = document.getElementById("test"); var parent = test.p ...
- 00.Oracle 11g安装
通过Docker安装Oracle 1.搜索镜像 先使用指令搜素远程仓库中的Oracle镜像 sudo docker search docker-oracle-xe-11g 2.拉取镜像 选择一个sta ...
- ONVIF网络摄像头(IPC)客户端开发—RTSP RTCP RTP加载H264视频流
前言: RTSP,RTCP,RTP一般是一起使用,在FFmpeg和live555这些库中,它们为了更好的适用性,所以实现起来非常复杂,直接查看FFmpeg和Live555源代码来熟悉这些协议非常吃力, ...
- [转帖]JVM中年轻代里的对象什么情况下进入老年代?以及老年代垃圾回收算法-标记整理算法
1.躲过15次GC之后进入老年代 系统刚启动时,创建的各种各样的对象,都是分配在年轻代里. 随着慢慢系统跑着跑着,年轻代满了,就会出发Minor GC ,可能1%的少量存活对像转移到空着的Surviv ...
- SQLServer备份恢复的总结-同名恢复与异名恢复
SQLServer备份恢复的总结 前言 GUI 搞一把. 命令行太多了也没人看 自己还能省点心 备份 备份数据库建议一定要选择: 备份选项中的 压缩->压缩备份 历史经验一个7.6G的数据库能够 ...
- [转帖]解释docker单机部署kraft模式kafka集群时,尝试各种方式的网络broker全部不通而启动失败的原因,并提示常见bug关注点
现象: controller节点与其他两个broker的通信失败.公网ip,宿主机ip,服务名,各种网络方式,都无法成功. 两点提示: 1.bug原因:因为单机内存不够用,设置了较低的 KAFKA_H ...
- shell的date的部分处理--需要记住..
在Linux中,可以使用date命令获取日期, date 获取当前完整日期 date --date="3 days ago" 获取3天前的完整日期 date --date=&quo ...
- [转帖]python读取配置文件获取所有键值对_python总结——处理配置文件(ConfigParser)
python处理ConfigParser 使用ConfigParser模块读写ini文件 (转载) ConfigParserPython 的ConfigParser Module中定义了3个类对INI ...