题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=4804

题意:给定一个图,0是不能放的,然后现在有1X1和1X2方块,最后铺满该图,使得1X1使用次数在C到D之间,1X2次数随便,问有几种放法?

解法:状压DP。dp[i][j][k]代表在第i行,当前状态为j,用了k次1*1的方格的方案数。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1e9+7;
int n,m,c,d;
int dp[102][1025][22];
char maze[110][12];
void dfs(int i, int pos, int now, int step, int j, int k){
	if(k+step > d) return;
	if(maze[i][pos]=='0'){
		if(j&(1<<pos)) dfs(i,pos+1,now|(1<<pos),step,j,k);
		else return;
	}
	else{
		if(pos==m) dp[i][now][k+step]=(dp[i][now][k+step]+dp[i-1][j][k])%mod;
		else{
			if(!((1<<pos)&j)) dfs(i,pos+1,now|(1<<pos),step,j,k);
			else{
				dfs(i,pos+1,now|(1<<pos),step+1,j,k);
				if(pos>0&&(!(now&(1<<(pos-1)))))
					dfs(i,pos+1,now|(1<<(pos-1))|(1<<pos),step,j,k);
				dfs(i,pos+1,now,step,j,k);
			}
		}
	}
}
int main(){
	while(~scanf("%d%d%d%d", &n,&m,&c,&d)){
		int mask = (1<<m)-1;
		memset(dp, 0, sizeof(dp));
		dp[0][mask][0]=1;
		for(int i=1; i<=n; i++){
			scanf("%s", maze[i]);
		}
		for(int i=1; i<=n; i++)
			for(int j=0; j<=mask; j++)
				for(int k=0; k<=d; k++)
					if(dp[i-1][j][k])
						dfs(i,0,0,0,j,k);
		int ans=0;
		for(int i=c; i<=d; i++)
			ans = (ans + dp[n][mask][i])%mod;
		if(ans < 0) ans += mod;
		printf("%d\n", ans);
	}
	return 0;
}