NC17890 方格填色

题目链接

题目

题目描述

给一个m x n的方格,Applese想要给方格填上颜色,每个格子可以是黑色或者白色。他要求左右相邻两格不能同为白色且相邻两列不能全为黑色。

求满足条件的方案数。

输入描述

输入两个整数m, n。(1m5,1n1018)

输出描述

输出答案对 109+7 取模的结果。

**示例1 **

输入

3 1

输出

8

示例2

输入

3 5

输出

1640

示例3

输入

5 5

输出

351032

题解

知识点:状压dp,运算优化。

注意到可以一列一列摆,设 0 代表黑色,1 代表白色,这样比反过来方便。设第 i 列状态为 st1 ,第 i1 列状态为 st2 ,于是首先 st1st2 自己都要满足 st & (st<<1) 不能为 1 ,即相邻不为白色,随后 st1 & st2 必须大于 0 ,即两列不能都为黑色。设 dp[i][st] 表示摆到第 i 列,状态 st 时的方案数,有转移方程:

dp[i][st1]=dp[i1][st2]

注意到 n 十分的大,考虑优化。发现转移方程只和这一列的 st1 和上一列的 st2 有关,并且对于一组 (st1,st2) 能否转移是不随 i 变化的,因此我们可以预先确定每一组 (st1,st2) 是否可以从 st2 转移到 st1。显然,用矩阵快速幂,可以解决这个问题了。假设 f(i,j) ,表示状态 (i,j) 是否可以转移,用 01 表示,于是 f(i,j)=!(i&j)(i|j)。矩阵构造如下:

(dp[n][0]dp[n][1]dp[n][2m1])=(f(0,0)f(1,0)f(2m1,0)f(0,1)f(1,1)f(2m1,1)f(0,2m1)f(1,2m1)f(2m1,2m1))n1(dp[1][0]dp[1][1]dp[1][2m1])

时间复杂度 O(8mlogn)

空间复杂度 O(4m)

代码

#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;
}
posted @   空白菌  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示