【Codeforces Gym - 101635C Macarons 】【矩阵快速幂+状压】【dfs时间换空间】

本文介绍了一种解决特定组合计数问题的算法:利用状压深度优先搜索(DFS)结合矩阵快速幂来高效计算1*1和1*2方格填充n*m矩阵的方法数。文章详细解释了如何通过状态压缩进行列间状态转移,构建邻接矩阵,并使用快速幂运算求解初始矩阵的高次幂,最终得到解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【链接】

http://codeforces.com/gym/101635/attachments

【题意】

求用1*1,1*2的方格填n*m的矩阵的方法数

【知识点】

状压dfs+矩阵快速幂

【分析】

每列状态的状态转移压缩,通过dfs状压求出每个状态的邻接矩阵,求出初始矩阵,再快速幂即可

【代码】

#include<stdio.h>  
#include<string.h>  
#define NN 256  
#define mod 1000000000  
typedef long long ll;
struct matrix  //设定为NN*NN的矩阵  
{
	ll mat[NN][NN];
}a, ans, c, d;
ll f[10];
ll n, m;
matrix operator	*(matrix a, matrix b) {
	matrix c;
	memset(c.mat, 0, sizeof(c.mat));
	for (ll i = 0; i<NN; i++) {
		for (ll k = 0; k<NN; k++) {
			if (a.mat[i][k] == 0)continue;
			for (ll j = 0; j<NN; j++)
				c.mat[i][j] = (c.mat[i][j] + (a.mat[i][k] % mod)*(b.mat[k][j] % mod)) % mod;
		}
	}
	return c;
}
matrix qpow(ll b)
{
	memset(d.mat, 0, sizeof(d.mat));
	for (ll i = 0; i<NN; i++) {
		for (ll j = 0; j<NN; j++) {
			if (i == j) d.mat[i][j] = 1;
			else d.mat[i][j] = 0;
		}
	}
	while (b>0) {
		if (b % 2 == 1)d = d * a;
		a = a * a;
		b >>= 1;
	}
	return d;
}
void dfs(ll pos, ll now, ll to) {
	if (pos >= n) {
		a.mat[now][to]++;
		return;
	}
	if (now&(1 << pos)) {
		dfs(pos + 1, now, to);
		dfs(pos + 1, now, to + f[pos]);
		if (pos + 1<n && (now&(1 << (pos + 1))))
			dfs(pos + 2, now, to + f[pos] + f[pos + 1]);
	}
	else dfs(pos + 1, now, to + f[pos]);
}
int main() {
	f[0] = 1;
	for (ll i = 1; i<10; i++)f[i] = f[i - 1] * 2;
	scanf("%lld%lld", &n, &m);
	for (ll state = 0; state<(1 << n); state++)
		dfs(0, state, 0);
	for (ll i = 0; i<(1 << n); i++)
		ans.mat[0][i] = a.mat[(1 << n) - 1][i];
	a = qpow(m - 1);
	ans = ans * a;
	printf("%lld\n", ans.mat[0][(1 << n) - 1]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值