[BZOJ2331]地板(插头DP)

Description

lxhgww的小名叫“小L”,这是因为他总是很喜欢L型的东西。小L家的客厅是一个的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板。现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案?

需要注意的是,L型地板的两端长度可以任意变化,但不能长度为0。铺设完成后,客厅里面所有没有柱子的地方都必须铺上地板,但同一个地方不能被铺多次。

R*C<=100

Solution

插头DP,用三进制表示状态,0表示无插头,1表示有插头且可以转向,2表示有插头但不可转向

转移如下,

  1. 00 To 22/10/01
  2. 11 To 00
  3. 10 To 20/01
  4. 20 To 00/02
  5. 01 To 10/02
  6. 02 To 00/20

Code

#include <cstdio>
#include <algorithm>
#define N 14
using namespace std;

const int mod=20110520;
int n,m,A[N],now,dp[2][N][200000];//滚动数组
char g[N][N];

int main(){
	A[0]=1;for(int i=1;i<=12;++i)A[i]=A[i-1]*3;
	scanf("%d%d\n",&n,&m);
	for(int i=1;i<=n;++i,scanf("\n"))
		for(int j=1;j<=m;++j)
			if(n>m) scanf("%c",&g[i][j]);else scanf("%c",&g[j][i]);
	if(n<m) swap(n,m);//将大的用来滚动
	dp[0][m][0]=1;
	for(int i=1;i<=n;++i){
		now^=1;
		for(int j=0;j<A[m];++j) dp[now][0][j*3]=dp[now^1][m][j];
		for(int j=1;j<=m;++j)
			for(int k=0;k<A[m+1];++k){
				int l=k/A[j-1]%3,r=k/A[j]%3;
				if(g[i][j]=='_'){
					if(!l&&!r) dp[now][j][k]=(dp[now][j-1][k+(A[j]<<1)+(A[j-1]<<1)]+dp[now][j-1][k+A[j]]+dp[now][j-1][k+A[j-1]])%mod;
					else if(l==1&&r==1) dp[now][j][k]=dp[now][j-1][k-A[j]-A[j-1]];
					else if(l==1&&!r) dp[now][j][k]=(dp[now][j-1][k+A[j-1]]+dp[now][j-1][k-A[j-1]+A[j]])%mod;
					else if(l==2&&!r) dp[now][j][k]=(dp[now][j-1][k-(A[j-1]<<1)]+dp[now][j-1][k-(A[j-1]<<1)+(A[j]<<1)])%mod;
					else if(!l&&r==1) dp[now][j][k]=(dp[now][j-1][k-A[j]+A[j-1]]+dp[now][j-1][k+A[j]])%mod;
					else if(!l&&r==2) dp[now][j][k]=(dp[now][j-1][k-(A[j]<<1)]+dp[now][j-1][k-(A[j]<<1)+(A[j-1]<<1)])%mod;
					else dp[now][j][k]=0;//注意清零
				}else if(!l&&!r) dp[now][j][k]=dp[now][j-1][k];else dp[now][j][k]=0;//
			}
	}
	printf("%d\n",dp[now][m][0]);
	return 0;
} 
posted @ 2018-01-08 21:20  void_f  阅读(310)  评论(0编辑  收藏  举报