头一次独自完成插头DP的题,发博客庆祝一下。
(不过我居然因为忘记取模错了一次)
发现n,m都很小,可以用插头DP。
可以把点看作格子。
用一个变量zt来记录当前位置在回路内部还是外部,便于思考。如果格子左边有一个横向的插头,那么用它左上角判断位置。不过这个不影响答案。
具体细节看代码。
#include<cstdio>
#include<iostream>
using namespace std;
const int md=123456791;
int n,m;
char s[40][20];
struct node{
int val,zt;
}q1[1<<15],q2[1<<15];
int dp1[1<<15],dp2[1<<15];
node *p=q1,*q=q2;
int *dp=dp1,*dq=dp2;
int num1,num2;
int a[40];
void printa(){
for(int i=0;i<=m;i++)
printf("%d",a[i]);
printf("\n");
}
void turn_out(int val){
for(int i=0;i<=m;i++){
a[i]=val&1;
val>>=1;
}
}
int turn_in(){
int val=0;
for(int i=m;i>=0;i--){
val<<=1;
val+=a[i];
}
return val;
}
void shift(){
for(int i=m;i>=1;i--)
a[i]=a[i-1];
a[0]=0;
}
void push_in(node st,int val){
if(!dq[st.val]) q[++num2]=st;
(dq[st.val]+=dp[val])%=md;
}
void dp_block(int k,node st){
turn_out(st.val);
if(k==1) shift();
int val,zt;
if(a[k-1]&&a[k])
{
a[k-1]=0,a[k]=0;
val=turn_in(),zt=st.zt^1;
push_in((node){val,zt},st.val);
return;
}
else if(a[k-1]&&!a[k])
{
if(k<m)
{
a[k-1]=0,a[k]=1;
val=turn_in(),zt=st.zt;
push_in((node){val,zt},st.val);
}
a[k-1]=1,a[k]=0;
val=turn_in(),zt=st.zt;
push_in((node){val,zt},st.val);
return;
}
else if(!a[k-1]&&a[k])
{
a[k-1]=1,a[k]=0;
val=turn_in(),zt=st.zt^1;
push_in((node){val,zt},st.val);
if(k<m)
{
a[k-1]=0,a[k]=1;
val=turn_in(),zt=st.zt^1;
push_in((node){val,zt},st.val);
}
return;
}
else if(!a[k-1]&&!a[k])
{
if(k<m)
{
a[k-1]=1,a[k]=1;
val=turn_in(),zt=st.zt;
push_in((node){val,zt},st.val);
}
return;
}
}
void dp_in(int k,node st){
turn_out(st.val);
if(k==1) shift();
int val,zt;
if(!a[k-1]&&!a[k]&&st.zt==1)
{
val=turn_in(),zt=st.zt;
push_in((node){val,zt},st.val);
}
}
void dp_out(int k,node st){
turn_out(st.val);
if(k==1) shift();
int val,zt;
if(!a[k-1]&&!a[k]&&st.zt==0)
{
val=turn_in(),zt=st.zt;
push_in((node){val,zt},st.val);
}
}
int main(){
// freopen("A1223.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);
num1=1,num2=0;
p[num1]=(node){0,0};
dp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=1;k<=num1;k++)
{
if(s[i][j]=='.') dp_block(j,p[k]);
else if(s[i][j]=='*') dp_in(j,p[k]);
else if(s[i][j]=='#') dp_out(j,p[k]);
dp[p[k].val]=0;
}
swap(dp,dq);
swap(p,q);
num1=num2,num2=0;
}
}
printf("%d\n",dp[0]);
return 0;
}