码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ2331】[SCOI2011]地板 插头DP

时间:2017-12-09 12:05:49      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:names   整数   name   img   clu   变化   mes   font   swa   

【BZOJ2331】[SCOI2011]地板

Description

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

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

技术分享图片

Input

输入的第一行包含两个整数,RC,表示客厅的大小。

接着是R行,每行C个字符。’_’表示对应的位置是空的,必须铺地板;’*’表示对应的位置有柱子,不能铺地板。

Output

输出一行,包含一个整数,表示铺满整个客厅的方案数。由于这个数可能很大,只需输出它除以20110520的余数。

Sample Input

2 2
*_
__

Sample Output

1

HINT

R*C<=100

题解:我们取R和C中小的那维做状态。显然状态是三维的:对于轮廓线上的每个位置,用0表示无插头,1表示有插头,并且这个L还没有拐弯,2表示有插头,并且L已经拐弯了。然后进行3*3的讨论吧!注意一个拐过弯的插头可以停止,一个没拐过弯的插头可以拐弯。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=177200;
const int P=20110520;
int n,m,k,tag,tot;
char str[110][110];
int dp[2][maxn],bt[20],m3[maxn];
inline void upd(int a) {dp[k][a]+=tag;	if(dp[k][a]>=P)	dp[k][a]-=P;}
int main()
{
	scanf("%d%d",&n,&m);
	int i,j,S,T,p,q,x,y;
	for(i=1;i<=n;i++)	scanf("%s",str[i]+1);
	if(n<m)
	{
		for(i=1;i<=m;i++)	for(j=1;j<i;j++)	swap(str[i][j],str[j][i]);
		swap(n,m);
	}
	for(i=bt[0]=1;i<=m+1;i++)	bt[i]=bt[i-1]*3;
	for(tot=bt[m+1],i=1;i<tot;i++)	m3[i]=i%3;
	dp[0][0]=1;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			k^=1;
			memset(dp[k],0,sizeof(dp[k]));
			for(S=0;S<tot;S++)	if(dp[k^1][S])
			{
				x=bt[j-1],y=bt[j],p=m3[S/x],q=m3[S/y],tag=dp[k^1][S],T=S-x*p-y*q;
				if(str[i][j]==‘*‘)
				{
					if(!p&&!q)	upd(T);
					continue;
				}
				if(!p&&!q)
				{
					if(i!=n&&j!=m)	upd(T+((x+y)<<1));
					if(i!=n)	upd(T+x);
					if(j!=m)	upd(T+y);
				}
				if(!p&&q==1)
				{
					if(i!=n)	upd(T+x);
					if(j!=m)	upd(T+(y<<1));
				}
				if(!p&&q==2)
				{
					if(i!=n)	upd(T+(x<<1));
					upd(T);
				}
				if(!q&&p==1)
				{
					if(j!=m)	upd(T+y);
					if(i!=n)	upd(T+(x<<1));
				}
				if(!q&&p==2)
				{
					if(j!=m)	upd(T+(y<<1));
					upd(T);
				}
				if(p==1&&q==1)	upd(T);
			}
		}
		for(S=tot-1;S>=0;S--)	dp[k][S]=(m3[S]>0)?0:dp[k][S/3];
	}
	printf("%d",dp[k][0]);
	return 0;
}//10 10 __________ __________ __________ __________ __________ __________ __________ __________ __________ __________

【BZOJ2331】[SCOI2011]地板 插头DP

标签:names   整数   name   img   clu   变化   mes   font   swa   

原文地址:http://www.cnblogs.com/CQzhangyu/p/8010802.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!