【矩阵快速幂】NC17890-方格填色
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给一个\(m * n\)的方格,Applese想要给方格填上颜色,每个格子可以是黑色或者白色。他要求左右相邻两格不能同为白色且相邻两列不能全为黑色。
求满足条件的方案数。
输入描述:
输入两个整数m, n。(1 ≤ m ≤ 5, 1 ≤ n ≤ 1e18)。
输出描述:
输出答案对1e9 + 7取模的结果。
示例1
输入
3 1
输出
8
示例2
输入
3 5
输出
1640
示例3
输入
5 5
输出
351032
思路
题意如题不用解读
因为\(m\)很小,我们可以考虑一列一列的去看,每个格子是黑色或者白色,那么每一列最多能有\(2^m\)个方案数,我们可以用一个动态规划来求方案数
设\(st\)是一个\(0\)到\(2^m - 1\)的一个数,看成是\(m\)位的二进制,表示涂色状态,0是白色,1是黑色
\(n\)特别大,这个状态是可以递推的,但不能用线性,这个时候可以使用一种常用的优化线性递推的数论知识,矩阵快速幂
那么可以设\(f(n,st) = \sum f(n-1,st')\),来构造一个转移矩阵,题目需要满足一些条件,没有相邻的两列中两个相邻的格为白色并且没有相邻两列全黑。
容易知道可以用限制条件\(st|st' = 2 ^m-1\)来得到第一个条件的可行方案,并且\(st,st'\)不能同为\(2^m-1\)来得到第二个条件的可行方案,设转移矩阵为\(trans\),那么\(trans.a[st][st']\)在两格条件都满足时为1,否则为0,一直往下递推可以知道:

最终答案为\(\sum_{st=0}^{2^m-1}f(n,st)\)
矩阵快速幂复杂度\(O((2^m)^3*logn)\)
(就写出了两个板子题把自己高兴坏了,不知道在高兴什么)
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;
}

浙公网安备 33010602011771号