Campus Design(hdu 4804 輪廓線dp)
阿新 • • 發佈:2018-11-25
題目連結:
題意:
有n*m個格子的矩形,有些格子不能放東西,其餘格子用1*2 、2*1 、1*1的木塊去填充,其中1*1的木塊的使用個數必須>=C且<=D,1*2和2*1的沒有限制,求能把矩形都填滿的方案數。
思路:
輪廓線DP模版(+解釋):【輪廓線DP】
1 | 1 | 1 | 1 | 1 |
1 | 1 | K4 | K3 | K2 |
K1 | K0 | now | ||
now格點表示當前已經處理到的位置,由於只能用1*2 、2*1 、1*1的木塊,所以紅色的格點必須已經放有東西,因為在接下去的所有處理中紅色格點已經不會再被處理到了。而藍色格點表示還能被後續處理到。
因此,輪廓線狀壓的表示不是按照縱座標大小從左到右,而是按照從左到右,從上至下的順序(K4..K0)來的。
dp[2][D][1<<m]:當前位置的運算只與上一個位置有關,因此只需要存2個位置的狀態。第二維表示1*1的木塊的使用個數。第三維表示狀態。初始時(也就是在(0,0)位置計算之前),它的上一行不存在,我們按假設-1行都是1的狀態算(-1行都是已經放滿了的),且此時1*1使用0個,即 dp[0][0][(1<<m)-1]=1 。
相關位運算:(設現在輪廓線狀壓的狀態為k)
now的上方格點(K4)的取值: k&(1<<(m-1)) ;
now的左邊格點(K0)的取值: k&1
用2*1的木塊: 因為要豎著放,所以K4的取值必須為0,放好後的新狀態:舊狀態刪去首位,末尾為1
用1*2的木塊: 因為要橫著放,所以K0的取值必須為0且K4的取值必須為1,放好後的新狀態:舊狀態刪去首位,末尾2位為1
不放:K4的取值必須為1,放好後的新狀態:舊狀態刪去首位,末尾為0
用1*1的木塊:K4的取值必須為1,放好後的新狀態:舊狀態刪去首位,末尾為1,且1*1的使用次數++
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5+10;
const ll mod = 1e9+7;
int n,m;
char mp[105][15];
int C,D;
ll dp[2][25][1<<11];
int main()
{
while(scanf("%d%d%d%d",&n,&m,&C,&D)!=EOF)
{
for(int i=0;i<n;i++)
scanf("%s",mp[i]);
memset(dp,0,sizeof(dp));
int cur=0;
dp[0][0][(1<<m)-1]=1;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cur^=1;
memset(dp[cur],0,sizeof(dp[cur]));
if(mp[i][j]=='1'){
for(int t=0;t<=D;t++){
for(int k=0;k<(1<<m);k++){
//豎放
if(i!=0&&(k&(1<<(m-1)))==0){
int now = (((k<<1)|1)&((1<<m)-1));
dp[cur][t][now]+=dp[cur^1][t][k];
dp[cur][t][now]%=mod;
}
//橫放
if(j!=0&&(k&1)==0&&(k&(1<<(m-1)))){
int now = (((k<<1)|3)&((1<<m)-1));
dp[cur][t][now]+=dp[cur^1][t][k];
dp[cur][t][now]%=mod;
}
//不放
if(k&(1<<(m-1))){
int now = ((k<<1)&((1<<m)-1));
dp[cur][t][now]+=dp[cur^1][t][k];
dp[cur][t][now]%=mod;
}
//放1*1
if(k&(1<<(m-1))){
int now = (((k<<1)|1)&((1<<m)-1));
dp[cur][t+1][now]+=dp[cur^1][t][k];
dp[cur][t+1][now]%=mod;
}
}
}
}
else{
for(int t=0;t<=D;t++){
for(int k=0;k<(1<<m);k++){
//不能放相當於這個地方已經是1
if(k&(1<<(m-1))){
int now = (((k<<1)|1)&((1<<m)-1));
dp[cur][t][now]+=dp[cur^1][t][k];
dp[cur][t][now]%=mod;
}
}
}
}
}
}
ll ans=0;
for(int i=C;i<=D;i++){
ans+=dp[cur][i][(1<<m)-1];
ans%=mod;
}
printf("%lld\n",ans);
}
return 0;
}