题目链接:
https://vjudge.net/contest/159644#problem/G
题意:
用1*2的砖去恰好铺满n*m的空间,有多少种方法
题解:
http://blog.csdn.net/xingyeyongheng/article/details/21692655
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 typedef long long ll; 6 #define MS(a) memset(a,0,sizeof(a)) 7 #define MP make_pair 8 #define PB push_back 9 const int INF = 0x3f3f3f3f; 10 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 11 inline ll read(){ 12 ll x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 ////////////////////////////////////////////////////////////////////////// 18 const int maxn = (1<<11)+10; 19 20 int n,m; 21 ll cnt[maxn],dp[maxn]; 22 bool mark[maxn]; 23 24 bool check(int x){ 25 while(x){ 26 if(x&1){ 27 x >>= 1; 28 if(!(x&1)) return false; 29 x >>= 1; 30 }else { 31 x >>= 1; 32 } 33 } 34 return true; 35 } 36 37 void init(){ 38 MS(mark); MS(cnt); 39 for(int i=0; i<(1<<m); i++){ 40 if(check(i)) 41 cnt[i]=1,mark[i]=true; 42 } 43 } 44 45 void DP(){ 46 for(int k=2; k<=n; k++){ 47 MS(dp); 48 for(int i=0; i<(1<<m); i++){ // 枚举本行的状态 49 for(int j=0; j<(1<<m); j++){ // 枚举上一行的状态,找到可以转移到第i行的状态 50 if((i|j) != (1<<m)-1) continue; 51 if(!mark[i&j]) continue; 52 dp[i] += cnt[j]; //i可以从j到达,则增加j的方案数 53 // mark[i&j] 是为了判断两行都是横着放的状态---> 1 1 54 // 1 1 55 // 如果是 i = 00110011 56 // j = 11011111 i&j=00010011 这是不合法的 57 58 } 59 } 60 for(int i=0; i<(1<<m); i++) cnt[i] = dp[i]; 61 } 62 } 63 64 int main(){ 65 while(cin>>n>>m && (n+m)){ 66 if(n<m) swap(n,m); //始终保持m<n,提高效率 67 init(); 68 DP(); 69 70 cout << cnt[(1<<m)-1] << endl; //输出最后一行到达时的状态必须全部是1 71 } 72 73 return 0; 74 } 75 // http://blog.csdn.net/xingyeyongheng/article/details/21692655