#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace acac
{
char A[30][30];
int hlist[300010][4],nex[300010][4],dy[300010][4],sz[10],dp[300010][5],zt,pre=1;
//哈希表前2,滚动计算大小,dp数组,0/1状态
const int mod=299993;
int ans;
void ins(int now,int num)//hash表加入,因为此处时空不足,所以必须用hash表qwq
{
int w=now%mod+1;
for(int i=hlist[w][zt];i;i=nex[i][zt])
{
if(dy[i][zt]==now)
{
dp[i][zt]+=num;
return ;
}
}
dy[++sz[zt]][zt]=now;
nex[sz[zt]][zt]=hlist[w][zt];
hlist[w][zt]=sz[zt];
dp[sz[zt]][zt]=num;
return ;
}
//zt:前,pre:后,0:无,1:left,2:right ->1:(,2:)
int main()
{
int n,m;
scanf("%lld%lld",&n,&m);
int edx=0,edy=0;//最后一个合法位置
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char ch=getchar();
while(ch!='.'&&ch!='*')
{
ch=getchar();
}
A[i][j]=ch;
if(ch=='.')edx=i,edy=j;
}
}
ins(0,1);
//4进制表示
for(int i=1;i<=n;i++)
{
for(int j=1;j<=sz[zt];j++)
{
dy[j][zt]<<=2;
}
//因为最后一位少一个->的插头,补上
for(int j=1;j<=m;j++)
{
memset(hlist,0,sizeof(hlist));
zt^=1,pre^=1;
sz[zt]=0;
// cout<<zt<<' '<<pre<<' '<<sz[pre]<<endl;
for(int k=1;k<=sz[pre];k++)
{
int now=dy[k][pre],val=dp[k][pre];
//cout<<now<<endl;
int ct1=(now>>(2*(j-1)))&3,ct2=(now>>(2*j))&3;
// cout<<ct1<<' '<<ct2<<' '<<i<<' '<<j<<' '<<val<<endl;
if(A[i][j]=='*')
{
if(!ct1&&!ct2)ins(now,val);//0000
}
else if(!ct1&&!ct2)//1001
{
if(A[i+1][j]=='.'&&A[i][j+1]=='.')ins(now+(9<<((j-1)*2)),val);
}
else if(ct1&&!ct2)//移位(注意j,j-1都右移了)
{
if(A[i+1][j]=='.')ins(now,val);
if(A[i][j+1]=='.')ins(now-(1<<((j-1)*2))*ct1+(1<<(j*2))*ct1,val);
}
else if(!ct1&&ct2)
{
if(A[i+1][j]=='.')ins(now-(1<<(j*2))*ct2+(1<<((j-1)*2))*ct2,val);
if(A[i][j+1]=='.')ins(now,val);
}
else if(ct1==1&&ct2==1)//括号序大概这样:xxx((xxx))xxx(显示的括号匹配),而要变为:xxxx()x(之前的变了)
{
int k=1;
for(int a=j+1;a<=n;a++)
{
int p=(now>>(2*a))&3;
if(p==1)k++;
if(p==2)k--;
if(!k)
{
ins(now-(1<<(j*2))-(1<<((j-1)*2))-(1<<(a*2)),val); //将第a位2->1;
break;
}
}
}
else if(ct1==2&&ct2==2)
{
int k=-1;
for(int a=j-2;a>=0;a--)
{
int p=(now>>(2*a))&3;
if(p==1)k++;
if(p==2)k--;
if(!k)
{
ins(now-(1<<(j*2))*2-(1<<((j-1)*2))*2+(1<<(a*2)),val); //将第a位1->2;
break;
}
}
}
else if(ct1==2&&ct2==1)//x(xx()x)xx->x(xxxxx)xx
{
ins(now-(1<<(j*2))-(1<<((j-1)*2))*2,val);
}
else if(edx==i&&edy==j)
{
// cout<<val<<endl;
ans+=val;
}
}
}
}
cout<<ans;
return 0;
}
}
#undef int
int main()
{
acac::main();
return 0;
}
才学dp,转移没看出问题:(