#1162 : 骨牌覆盖问题·三
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
前两周里,我们讲解了2xN,3xN骨牌覆盖的问题,并且引入了两种不同的递推方法。
这一次我们再加强一次题目,对于给定的K和N,我们需要去求KxN棋盘的覆盖方案数。
提示:KxN骨牌覆盖
输入
第1行:2个整数N。表示棋盘宽度为k,长度为N。2≤K≤7,1≤N≤100,000,000
输出
第1行:1个整数,表示覆盖方案数 MOD 12357
样例输入
2 62247088
样例输出
1399
#include<cstdio>
#include<cstring>
const int maxn=1<<7;
const int mod=12357;
struct mat{
int m[maxn][maxn];
};
int k,n,N;
mat mul(mat a,mat b){
mat c;
memset(c.m,0,sizeof(c.m));
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
for(int k=0;k<N;k++){
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
}
return c;
}
mat matpow(mat a,int n){
mat c;
memset(c.m,0,sizeof(c));
for(int i=0;i<N;i++)c.m[i][i]=1;
while(n){
if(n&1)c=mul(c,a);
a=mul(a,a);
n>>=1;
}
return c;
}
void dfs(int l,int c,int p,mat&a){
if(l>k)return;
if(l==k){
a.m[p][c]++;
return ;
}
dfs(l+2,c<<2|3,p<<2|3,a);
dfs(l+1,c<<1|1,p<<1,a);
dfs(l+1,c<<1,p<<1|1,a);
}
int main()
{
while(~scanf("%d%d",&k,&n)){
if(n*k%2==1){
puts("0");
continue;
}
N=1<<k;
mat tmp;
memset(tmp.m,0,sizeof(tmp.m));
dfs(0,0,0,tmp);
mat c;
memset(c.m,0,sizeof(c.m));
for(int i=0;i<N;i++)c.m[i][i]=1;
printf("%d\n",mul(c,matpow(tmp,n)).m[N-1][N-1]);
}
return 0;
}