版权声明:希望能在自己成长的道路上帮到更多的人,欢迎各位评论交流 https://blog.csdn.net/yiqzq/article/details/82720047
原题地址:https://www.nowcoder.com/acm/contest/190/J
思路:我们可以观察数据范围发现, 和 的差距特别大.然后 最大只有 并且我们经过递推可以发现当前列的状态只与前一列有关,所以这题很显然可以用状压 来写.但是 又特别大,所以可以考虑使用矩阵快速幂来加快递推.
具体方法是先构造出递推的矩阵,然后讨一个矩阵快速幂的板子,最后直接统计个数就行了.
ac代码:
#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
ll n, m, tot;
struct mat {//定义矩阵结构体
ll m[100][100];
mat() {
memset(m, 0, sizeof(m));
}
};
mat operator * (mat a, mat b) {//定义矩阵乘法
mat ans;
ll x = 0;
for (int i = 0; i < tot; i++) {
for (int j = 0; j < tot; j++) {
x = 0;
for (int k = 0; k < tot; k++) {
x = (x + a.m[i][k] * b.m[k][j]) % mod;
}
ans.m[i][j] = x;
}
}
return ans;
}
mat init(mat &a) {//初始化单位矩阵
for (int i = 0; i < tot; i++) {
a.m[i][i] = 1;
}
return a;
}
mat mat_pow(mat a, ll n) {//矩阵快速幂
mat ans = init(ans);
while (n) {
if (n & 1) ans = ans * a;
a = a * a;
n >>= 1;
}
return ans;
}
int main() {
scanf("%lld%lld", &n, &m);//n行m列,和题目中定义反的
mat a;
tot = 1 << n;
for (int i = 0; i < tot; i++) {//初始化所要矩阵快速幂的矩阵
for (int j = 0; j < tot; j++) {
if (i == 0 && j == 0) continue;//这两个if就是题目的两个限制
if ((i & j) == 0) a.m[i][j] = 1;
}
}
mat bas, ans;
bas = mat_pow(a, m - 1);
for (int i = 0; i < tot; i++) ans.m[0][i] = 1;//初始化第1列,因为第一列所有情况都合法
ans = ans * bas;
ll cnt = 0;
for (int i = 0; i < tot; i++) {//统计结果
cnt = cnt + ans.m[0][i];
cnt %= mod;
}
printf("%lld\n", cnt);
return 0;
}