Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 18359 | Accepted: 10487 |
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
插头dp模板题之:1*2的多米诺骨牌放满网格纸的方案数。
这个玩意有超级多变种,比如说:
1.不放满
2.不允许有贯穿网格的直线
3.矩阵版(行和列其中一个<=6另一个血大)
4.(骨牌形状的多样性)
当然这些本质都是一样的:插头dp。
这种题的共同特点就是不能像普通状压dp一样把整行整列当做状态的一部分,这样不如把
适合题目的轮廓线当成状态的一部分来的简单。
(留个坑,基于连通性的状压dp还完全不会(据说转移方案一般都是两位数写起来贼带劲hhhh))
#include<iostream> #include<cstring> #include<algorithm> #include<cstdlib> #include<cstdio> #include<cmath> #define ll long long using namespace std; ll f[2][3000],n,m,ans; int ci[30],now,nxt,to; int main(){ ci[0]=1; for(int i=1;i<=20;i++) ci[i]=ci[i-1]<<1; while(scanf("%lld%lld",&n,&m)==2&&n&&m){ if(n>m) swap(n,m); now=ans=0,memset(f,0,sizeof(f)); /* if(n==1){ if(m&1) puts("0"); else printf("%d\n",m>>1); continue; } */ f[0][ci[n]-1]=1; for(int i=0;i<m;i++) for(int j=0;j<n;j++){ nxt=now^1; memset(f[nxt],0,sizeof(f[nxt])); for(int S=0;S<ci[n];S++){ if(!(S&ci[n-1])){ //竖着放 to=(S<<1)|1; f[nxt][to]+=f[now][S]; }else{ if(j&&!(S&1)){ //横着放 to=((S<<1)|3)^ci[n]; f[nxt][to]+=f[now][S]; } //不放 f[nxt][(S<<1)^ci[n]]+=f[now][S]; } } now=nxt; } ans=f[now][ci[n]-1]; printf("%lld\n",ans); } return 0; }