链接:点击打开链接
题意:我们有一个kxN的长条形棋盘,然后用1x2的骨牌去覆盖整个棋盘。对于这个棋盘,一共有多少种不同的覆盖方法
代码:
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const long long MOD=12357;
long long K,N,S;
struct node{
long long m[128][128];
}P,I;
node mul(node a,node b){
node c;
long long i,j,k,tmp;
for(i=0;i<S;i++){
for(j=0;j<S;j++){
tmp=0;
for(k=0;k<S;k++)
tmp=(tmp+a.m[i][k]*b.m[k][j]%MOD)%MOD;
c.m[i][j]=tmp;
}
}
return c;
}
node quickmod(node a,long long b){
long long i,j;
while(b){
if(b&1)
I=mul(I,a);
b>>=1;
a=mul(a,a);
}
return I;
}
void dfs(long long sta,long long dep,long long s,long long ss){
if(dep==K){
P.m[ss][s]=1;
return;
}
if((sta&3)==3){ //i+1行横放或不放
dfs(sta>>2,dep+2,s|(1<<dep)|(1<<(dep+1)),ss);
dfs(sta>>2,dep+2,s,ss);
}
if((sta&1)==0) //i+1行竖放
dfs(sta>>1,dep+1,s|(1<<dep),ss);
if((sta&1)==1)
dfs(sta>>1,dep+1,s,ss); //i+1行不放
} //对于k*n的铺地砖则dfs构造转移矩阵
int main(){ //但是当k很大或者有其他限制条件时,就不能
long long i,j; //通过矩阵转移来完成,则需要轮廓线dp,但
while(scanf("%lld%lld",&K,&N)!=EOF){ //但问题不是很复杂时,还是建议优先考虑矩阵
S=1ll<<K; //转移,代码量比较小,考虑的细节比较少
for(i=0;i<S;i++)
for(j=0;j<S;j++){
P.m[i][j]=0;
I.m[i][j]=(i==j);
}
for(i=0;i<S;i++)
dfs(i,0,0,i);
P=quickmod(P,N); //复杂度O(logN*(2^k)^3)
printf("%lld\n",P.m[S-1][S-1]); //初始或第0行S-1状态为1
}
return 0;
}