[ 插头DP ] BZOJ1814

%%%g1n0st

可以看cdq的ppt

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=13;
const int M=200000;
int k,n,m;
char s[N];
bool c[N][N],b;
int h[2][M],nx[2][M],t[2][M],tot[2];
int p[N<<1];
int lsti,lstj;
ll f[2][M],y,Ans;
inline void Add(int x){
    int s=x%M;
    for(int i=h[b][s];i;i=nx[b][i])
    if(t[b][i]==x){
        f[b][i]+=y;
        return;
    }
    f[b][++tot[b]]=y;
    t[b][tot[b]]=x;
    nx[b][tot[b]]=h[b][s];
    h[b][s]=tot[b];
}
inline void Update(int j,int k){
    if(j==m)k<<=2;
    Add(k);
}
int main(){
    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]=='.')c[i][j]=1,lsti=i,lstj=j;
    }
    p[0]=1;
    for(int i=1;i<=(m<<1|1);i++)p[i]=p[i-1]<<1;
    y=1;
    Add(0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            b^=1;tot[b]=0;
            memset(h[b],0,sizeof(h[b]));
            for(int k=1;k<=tot[b^1];k++){
                int s=t[b^1][k];y=f[b^1][k];
                int p1=(s>>(j-1<<1))&3,p2=(s>>(j<<1))&3;
                if(!c[i][j]){
                    if(p1||p2)continue;
                    Update(j,s);
                    continue;
                }
                if(!p1&&!p2){
                    if(c[i][j+1]&&c[i+1][j])Update(j,s+p[j-1<<1]+p[j<<1|1]);
                }else
                if(!p1&&p2){
                    if(c[i][j+1])Update(j,s);
                    if(c[i+1][j])Update(j,s-(p[j<<1]-p[j-1<<1])*p2);
                }else
                if(p1&&!p2){
                    if(c[i][j+1])Update(j,s+(p[j<<1]-p[j-1<<1])*p1);
                    if(c[i+1][j])Update(j,s);
                }else
                if(p1+p2==2){
                    int cur=1;
                    for(int t=j+1;t<=m;t++){
                        int P=(s>>(t<<1))&3;
                        if(P==1)cur++;else if(P==2)cur--;
                        if(!cur){
                            s-=p[t<<1];
                            break;
                        }
                    }
                    Update(j,s-p[j-1<<1]-p[j<<1]);
                }else
                if(p1+p2==4){
                    int cur=1;
                    for(int t=j-2;t>=0;t--){
                        int P=(s>>(t<<1))&3;
                        if(P==2)cur++;else if(P==1)cur--;
                        if(!cur){
                            s+=p[t<<1];
                            break;
                        }
                    }
                    Update(j,s-p[j-1<<1|1]-p[j<<1|1]);
                }else
                if(p1==2&&p2==1)Update(j,s-p[j-1<<1|1]-p[j<<1]);else
                if(p1==1&&p2==2&&i==lsti&&j==lstj)Ans+=y;
            }
        }
    cout<<Ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值