Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 15295 | Accepted: 8820 |
Description
Expert as he was in this material, he saw at a glance that he'll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won't turn into a nightmare!
Input
Output
Sample Input
1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0
Sample Output
1 0 1 2 3 5 144 51205
Source
/* 已经给了时间看题解了,正式练习一道题三天之内不准再看题解! */ #include <iostream> #include <stdio.h> #include <string.h> #define N (1<<12)+5 #define M 12 /* 用1表示当前小方格填满了,0表示没填满,初始化第一行的状态然后递推到最后一行 */ using namespace std; long long dp[M][N];//dp[i][j]表示第i行j种状态做多有多少种排列方式 int n,m; bool check(int x)//判断是不是有连续个奇数个1;当有连续奇数个1的时候那么这一行横着放的肯定是不会填满的 { int s=0; while(x) { if(x&1)s++; else { if(s&1)return false; s=0; } x>>=1; } if(s&1)return false; return true; } int main() { ///for(int i=0;i<30;i++) // cout<<"i="<<i<<" "<<check(i)<<endl; //cout<<endl; //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d%d",&n,&m)!=EOF&&n&&m) { if((n*m)%2)//如果乘积是奇数的话是肯定铺不满的 { printf("0\n"); continue; } if(n<m)//这里做一个剪枝,使m永远是小的那个,能减少不少循环的次数 { int tmp=n; n=m; m=tmp; } int tol=(1<<m); memset(dp,0,sizeof dp); for(int i=0;i<tol;i++)//初始第一行的状态 if(check(i)) dp[1][i]=1; for(int i=1;i<n;i++)//由i行推出i+1行 for(int j=0;j<tol;j++)//枚举上一个状态 if(dp[i][j]!=0)//上一个状态为零没计算意义 { for(int k=0;k<tol;k++) { if( (j|k)==tol-1 && check(j&k) )//这一步很精妙,(j|k)==tol-1保证了肯定能填满上一行,check(j&k)保证了这一行中横着放的小木块绝对能填满 dp[i+1][k]+=dp[i][j]; } } printf("%lld\n",dp[n][tol-1]); } return 0; }