题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5434
官方题解:
这个题用状态转移得到矩阵,再矩阵快速幂就可以了。
合体象的攻击范围是变少了的,我们可以理解为,一个小象会对自身的四个正方向产生保护,可以得到结论,只要附近有小象,我们就可以放。可以枚举 i 行的所有状态和 i−1 行的所有状态,判断是否可以转移。如果在第 i 行的 j 列上放了小象,那么只有在 i−1 行 j 列没有小象, i 行 j−1 列没有放小象 i−1 行 j−1 列有小象,或者 i 行 j+1 列没有小象 i−1 行 j+1 列有小象时,状态是不能转移的。
将状态转移方程改为矩阵,最后矩阵快速幂就可以了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn = 150;
const int mod = 1000000007;
struct Matrix
{
int n,m;
int val[maxn][maxn];
Matrix(){}
Matrix(int n,int m) :n(n),m(m){}
void init(int _n,int _m)
{
n = _n;
m = _m;
}
friend Matrix operator * (const Matrix& mat1, const Matrix& mat2)
{
Matrix ret(mat1.n,mat2.m);
for (int i = 0; i < ret.n; i++)
for (int j = 0; j < ret.m; j++)
{
ret.val[i][j] = 0;
for (int k = 0; k < mat1.m; k++)
{
ret.val[i][j] += (LL)mat1.val[i][k] * mat2.val[k][j]%mod;
ret.val[i][j] %= mod;
}
}
return ret;
}
};
int n,m,bit;
Matrix mat,ans;
bool isOK(int s1,int s2)
{
/* int tmp = s1 & s2;
for(int i = 0; i < m; i++)
if(!(tmp & (1<<i)))
{
if(tmp & (1<<i+1)) continue;
if((s1 & (1<<i)) && !(s2 & (1<<i+1))) return false;
if((s2 & (1<<i)) && !(s1 & (1<<i+1))) return false;
}
return true;*/
for (int i = 0; i < m; i++)
{
if((s1 & (1 << i)) && !(s2 & (1 << i)))
{
int j;
j = i - 1;
if(j >= 0)
if((s2 & (1 << j)) && !(s1 & (1 << j))) return false;
j = i + 1;
if(j < m)
if((s2 & (1 << j)) && !(s1 & (1 << j))) return false;
}
}
return true;
}
void power(Matrix &mat,Matrix &ans,int b)
{
while(b > 0)
{
if(b & 1) ans = mat * ans;
mat = mat * mat;
b >>= 1;
}
}
void init()
{
mat.init(bit,bit);
for(int i = 0; i < bit; i++)
for(int j = 0; j < bit; j++)
{
if(isOK(i,j)) mat.val[i][j] = 1;
else mat.val[i][j] = 0;
}
ans.init(bit,1);
for(int i = 0; i < bit; i++)
ans.val[i][0] = 1;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
bit = 1 << m;
init();
power(mat,ans,n-1);
int res = 0;
for(int i = 0; i < bit; i++)
res = (res + ans.val[i][0]) % mod;
printf("%d\n",res);
}
return 0;
}