https://www.luogu.com.cn/problem/P5056
学习了模板题https://www.cnblogs.com/y2823774827y/p/10140757.html
关键在于知道b1b2是你枚举的那个方块左边和上边的插头,b1是竖着的边的插头,b2是横着的边的插头。
然后1表示是一个条线左端点,2表示是1条线右端点,用4进制来存012的状态,再讨论状压的转移,8种情况怎么转移
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=15;
const int hs=299987;
int n,m,ex,ey,now,last,mt,cnt[2];
ll ans;
int hd[hs+3],nxt[2<<24],inc[maxl],mark[hs+3];
int a[maxl][maxl],que[2][2<<24];
ll val[2][2<<24];
char s[maxl];
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
if(s[j]=='.')
{
a[i][j]=1;
ex=i;ey=j;
}
}
inc[0]=1;
for(int i=1;i<maxl;i++)
inc[i]=inc[i-1]<<2;
}
inline void insert(int bit,ll num)
{
int u=bit%hs+1;
if(mark[u]!=mt)
hd[u]=0,mark[u]=mt;
for(int i=hd[u];i;i=nxt[i])
if(que[now][i]==bit)
{
val[now][i]+=num;
return;
}
nxt[++cnt[now]]=hd[u];
hd[u]=cnt[now];
que[now][cnt[now]]=bit;
val[now][cnt[now]]=num;
}
inline void mainwork()
{
int bit,b1,b2,top;ll num;
cnt[now]=1;val[now][1]=1;que[now][1]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=cnt[now];j++)
que[now][j]<<=2;
for(int j=1;j<=m;j++)
{
++mt;
last=now;now^=1;
cnt[now]=0;
for(int k=1;k<=cnt[last];k++)
{
bit=que[last][k];num=val[last][k];
b1=(bit>>((j-1)*2))%4;
b2=(bit>>(j*2))%4;
if(!a[i][j])
{
if(!b1 && !b2)
insert(bit,num);
}else if(!b1 && !b2)
{
if(a[i+1][j] && a[i][j+1])
insert(bit^inc[j-1]^(inc[j]*2),num);
}else if(b1 && !b2)
{
if(a[i+1][j])
insert(bit,num);
if(a[i][j+1])
insert(bit^(inc[j-1]*b1)^(inc[j]*b1),num);
}else if(!b1 && b2)
{
if(a[i][j+1])
insert(bit,num);
if(a[i+1][j])
insert(bit^(inc[j]*b2)^(inc[j-1]*b2),num);
}
else if(b1==1 && b2==1)
{
top=1;
for(int l=j+1;l<=m;l++)
{
if((bit>>(l*2))%4==1)
++top;
if((bit>>(l*2))%4==2)
--top;
if(!top)
{
insert((bit^inc[j-1]^inc[j])-inc[l],num);
break;
}
}
}else if(b1==2 && b2==2)
{
top=1;
for(int l=j-2;l>=0;--l)
{
if((bit>>(l*2))%4==1)
--top;
if((bit>>(l*2))%4==2)
++top;
if(!top)
{
insert((bit^(inc[j-1]*2)^(inc[j]*2))+inc[l],num);
break;
}
}
}else if(b1==2 && b2==1)
insert(bit^(inc[j-1]*2)^inc[j],num);
else if(i==ex && j==ey)
ans+=num;
}
}
}
}
inline void print()
{
printf("%lld",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}