您的位置:首页 > 其它

BZOJ2331:[SCOI2011]地板——题解

2018-01-10 22:37 190 查看

http://www.lydsy.com/JudgeOnline/problem.php?id=2331

题面复制于洛谷

题目描述

lxhgww的小名叫”小L“,这是因为他总是很喜欢L型的东西。小L家的客厅是一个R*C的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板。现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案?需要注意的是,如下图所示,L型地板的两端长度可以任意变化,但不能长度为0。

 

铺设完成后,客厅里面所有没有柱子的地方都必须铺上地板,但同一个地方不能被铺多次。

输入输出格式

输入格式:

输入的第一行包含两个整数,R和C,表示客厅的大小。接着是R行,每行C个字符。'_'表示对应的位置是空的,必须铺地板;'*'表示对应的位置有柱子,不能铺地板。

输出格式:

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

输入输出样例

输入样例#1: 
2 2
*_
__
输出样例#1: 
1
输入样例#2: 
3 3
___
_*_ ___
输出样例#2: 
8

参考了:https://www.geek-share.com/detail/2638985546.html

我终于可以告别插头dp啦233333……<—此人已疯

这道题的难点在于将插头dp的插头的定义进行修改。

0:无插头

1:有插头且当前格子所在的地板能再转弯。

2:有插头且当前格子所在的地板不能再转弯。

 有了这些就可以按照插头dp的思想进行分情况讨论了:

(摘自参考博客)

1.00-->22 或 10 或 01

2.11-->00

3.10-->20 或 01

   20-->00 或 02

4.01-->10 或 02

   02-->00 或 20

 最终把所有情况枚举累加即可。

PS:第二种情况的11转换成了00实质上是11相交的地方变成了这块地板的转折点(也可以理解为两块地板并在了一起)。

#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int INF=2147483647;
const int mod=300000;
const int M=1000005;
const int p=20110520;
struct node{
int to,nxt;
}edge[M];
int head[M],cnt;
int n,m;
bool mp[105][105];
int cur,pre;
int state[2][M];
ll ans[2][M],cntt;
int tot[2];
int bit[15];
inline void getbit(){
for(int i=1;i<15;i++)bit[i]=i<<1;
return;
}
inline void add(int u,int v){
cnt++;
edge[cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
return;
}
void insert(int now,ll num){
int u=now%mod;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(state[cur][v]==now){
ans[cur][v]+=num%p;
ans[cur][v]%=p;
return;
}
}
add(u,++tot[cur]);
state[cur][tot[cur]]=now;
ans[cur][tot[cur]]=num%p;
return;
}
void plugdp(){
cur=0;
tot[cur]=1;
ans[cur][1]=1;
state[cur][1]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=tot[cur];j++){
state[cur][j]<<=2;
}
for(int j=1;j<=m;j++){
memset(head,0,sizeof(head));cnt=0;
pre=cur,cur^=1;
tot[cur]=0;
for(int k=1;k<=tot[pre];k++){
int now=state[pre][k];
ll num=ans[pre][k]%p;
int is_down=(now>>bit[j-1])%4;
int is_right=(now>>bit[j])%4;
if(!mp[i][j]){
if(!is_down&&!is_right)
insert(now,num);
}
else if(!is_down&&!is_right){
if(mp[i+1][j])
insert(now+(1<<bit[j-1]),num);
if(mp[i][j+1])
insert(now+(1<<bit[j]),num);
if(mp[i][j+1]&&mp[i+1][j])
insert(now+2*(1<<bit[j-1])+2*(1<<bit[j]),num);
}
else if(is_down&&!is_right){
if(is_down==1){
if(mp[i+1][j])insert(now+(1<<bit[j-1]),num);
if(mp[i][j+1])insert(now-(1<<bit[j-1])+(1<<bit[j]),num);
}else{
insert(now-2*(1<<bit[j-1]),num);
if(mp[i][j+1])insert(now-2*(1<<bit[j-1])+2*(1<<bit[j]),num);
}
}
else if(!is_down&&is_right){
if(is_right==1){
if(mp[i+1][j])insert(now+(1<<bit[j-1])-(1<<bit[j]),num);
if(mp[i][j+1])insert(now+(1<<bit[j]),num);
}else{
insert(now-2*(1<<bit[j]),num);
if(mp[i+1][j])insert(now+2*(1<<bit[j-1])-2*(1<<bit[j]),num);
}
}
else if(is_down==1&&is_right==1)
insert(now-(1<<bit[j-1])-(1<<bit[j]),num);
}
}
}
for(int k=1;k<=tot[cur];k++)cntt+=ans[cur][k];
return;
}
int main(){
getbit();
scanf("%d%d",&n,&m);
if(n<m){
swap(n,m);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
char ch=getchar();
while(ch!='*'&&ch!='_')ch=getchar();
if(ch=='_')mp[j][i]=1;
}
}
}else{
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch=getchar();
while(ch!='*'&&ch!='_')ch=getchar();
if(ch=='_')mp[i][j]=1;
}
}
}
plugdp();
printf("%lld\n",cntt);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: