【矩阵快速幂】NC17890-方格填色

题目链接

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 32768K,其他语言65536K

64bit IO Format: %lld

题目描述

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

求满足条件的方案数。

输入描述:

输入两个整数m, n。(1 ≤ m ≤ 5, 1 ≤ n ≤ 1e18)。

输出描述:

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

示例1

输入

3 1

输出

8

示例2

输入

3 5

输出

1640

示例3

输入

5 5

输出

351032

思路

题意如题不用解读

因为m很小,我们可以考虑一列一列的去看,每个格子是黑色或者白色,那么每一列最多能有2m个方案数,我们可以用一个动态规划来求方案数

st是一个02m1的一个数,看成是m位的二进制,表示涂色状态,0是白色,1是黑色

n特别大,这个状态是可以递推的,但不能用线性,这个时候可以使用一种常用的优化线性递推的数论知识,矩阵快速幂

那么可以设f(n,st)=f(n1,st),来构造一个转移矩阵,题目需要满足一些条件,没有相邻的两列中两个相邻的格为白色并且没有相邻两列全黑。

容易知道可以用限制条件st|st=2m1来得到第一个条件的可行方案,并且st,st不能同为2m1来得到第二个条件的可行方案,设转移矩阵为trans,那么trans.a[st][st]在两格条件都满足时为1,否则为0,一直往下递推可以知道:

最终答案为st=02m1f(n,st)

矩阵快速幂复杂度O((2m)3logn)

(就写出了两个板子题把自己高兴坏了,不知道在高兴什么)

AC代码

#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define int long long
#define ull unsigned long long
#define PII pair<int,int>
#define endl '\n'
const int N = 40;
const int mod = 1e9 + 7;
const double pi = acos(-1.0);
typedef long long ll;
int t, n, m, M;
struct Matrix {//矩阵初始化,乘法重载
	int a[N][N];//2^5只有32,开40*40足够
	Matrix()
	{
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < m; j++) {
				a[i][j] = 0;
			}
		}
	}
	Matrix operator * (const Matrix& Ma_) const
	{
		Matrix res;
		for (int i = 0; i < m; ++i) {
			for (int j = 0; j < m; ++j) {
				for (int k = 0; k < m; ++k) {
					res.a[i][j] = (res.a[i][j] + a[i][k] * Ma_.a[k][j] % mod) % mod;
				}
			}
		}
		return res;
	}
};
Matrix quickpow(Matrix res,Matrix sta, ll b)//快速幂板子
{
	while (b > 0)
	{
		if (b & 1) res = res * sta;
		sta = sta * sta;
		b >>= 1;
	}
	return res;
}
void solve()
{
	m = (1 << M);
	Matrix state;
	Matrix trans;
	for (int i = 0; i < m; i++) {
			state.a[i][i] = 1;
	}
	for (int i = 0; i < m; i ++) {
		for (int j = 0; j < m; j ++) {
			if ((i | j)) {
				int flag = 0;
				for (int k = 0; k <= M; k ++) {
					if (((1 << k) & i) & ((1 << k) & j)) {
						flag = 1; 
						break;
					}
				}
				if (flag == 1)continue;
				trans.a[i][j] = 1;
			}
		}
	}//根据条件构造转移矩阵

	state = quickpow(state, trans, (n - 1));//快速幂

	int ans = 0;
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < m; j++) {
			ans =  (ans + state.a[i][j] + mod) % mod;
		}
	}
	cout << (ans + mod) % mod << endl;//方案数累加输出,注意取模
	return;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	while (cin >> M >> n) {
		solve();
	}
	return 0;
}
posted @   TomiokapEace  阅读(275)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
点击右上角即可分享
微信分享提示