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

【BZOJ 2331】 [SCOI2011]地板

时间:2015-04-03 09:26:10      阅读:131      评论:0      收藏:0      [点我收藏+]

标签:bzoj   oi   插头dp   

2331: [SCOI2011]地板

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 598  Solved: 264
[Submit][Status][Discuss]

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

Source


插头dp。


用0表示没有插头,1表示有插头且可以转弯,2表示有插头但不能转弯。


接下来就是枚举各种转移了。


1.00-->22 或 10 或 01


2.11-->00


3.10-->20 或 01

   20-->00 或 02


4.01-->10 或 02

   02-->00 或 20


#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#define M 200005
#define mod 20110520
using namespace std;
char s[105];
int bit[105],h[50005],tot,now,pre,a[105][105],n,m,f[2][M],state[2][M],total[2];
struct edge
{
	int y,ne;
}e[M];
void Solve(int s,int num)
{
	int pos=s%50000;
	for (int i=h[pos];i;i=e[i].ne)
		if (state[now][e[i].y]==s)
		{
			(f[now][e[i].y]+=num)%=mod;
			return;
		}
	total[now]++;
	state[now][total[now]]=s;
	f[now][total[now]]=num;
	e[++tot].y=total[now],e[tot].ne=h[pos],h[pos]=tot;
}
void Plugdp()
{
	now=0;
	f[now][1]=1;
	state[now][1]=0;
	total[now]=1;
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=total[now];j++)
			state[now][j]<<=2;
		for (int j=1;j<=m;j++)
		{
			pre=now,now=pre^1;
		    memset(f[now],0,sizeof(f[now]));
			total[now]=0;
			tot=0;
			memset(h,0,sizeof(h));
			for (int k=1;k<=total[pre];k++)
			{
				int s=state[pre][k];
				int num=f[pre][k];
				if (!num) continue;
				int p=(s>>bit[j-1])%4,q=(s>>bit[j])%4;
				if (!a[i][j])
				{
					if (!p&&!q)
						Solve(s,num);
				}
				else if (!p&&!q)
				{
					if (a[i][j+1])
						Solve(s+(1<<bit[j]),num);
					if (a[i+1][j])
						Solve(s+(1<<bit[j-1]),num);
					if (a[i][j+1]&&a[i+1][j])
						Solve(s+(1<<(bit[j-1]+1))+(1<<(bit[j]+1)),num);
				}
				else if (p&&q)
				{
					if (p==1&&q==1)
					{
						s=s-(1<<bit[j-1])-(1<<bit[j]);
						Solve(s,num);
					}
				}
				else if (!q)
				{
					if (p==1)
					{
						s=s-(1<<bit[j-1]);
						if (a[i+1][j]) 
							Solve(s+(1<<(bit[j-1]+1)),num);
						if (a[i][j+1])
							Solve(s+(1<<bit[j]),num);
					}
					else
					{
						s=s-(1<<(bit[j-1]+1));
						Solve(s,num);
						if (a[i][j+1])
							Solve(s+(1<<(bit[j]+1)),num);
					}
				}
				else
				{
					if (q==1)
					{
						s=s-(1<<bit[j]);
						if (a[i][j+1])
							Solve(s+(1<<(bit[j]+1)),num);
						if (a[i+1][j])
							Solve(s+(1<<bit[j-1]),num);
					}
					else
					{
						s=s-(1<<(bit[j]+1));
						Solve(s,num);
						if (a[i+1][j])
							Solve(s+(1<<(bit[j-1]+1)),num);
					}
				}
			}
		}
	}
}
int main()
{
	for (int i=0;i<=100;i++)
		bit[i]=i<<1;
    scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for (int j=1;j<=m;j++)
			if (n<m) a[j][i]=s[j]=='_';
		    else a[i][j]=s[j]=='_';
	}
	if (n<m) swap(n,m);
	Plugdp();
	cout<<f[now][1]<<endl;
	return 0;
}

技术分享


感悟:

1.wa是没有清空f[now]数组


2.根据题目要求改变插头的含义

【BZOJ 2331】 [SCOI2011]地板

标签:bzoj   oi   插头dp   

原文地址:http://blog.csdn.net/regina8023/article/details/44838887

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