P5056 【模板】插头dp

P5056 【模板】插头dp

括号表示法(转) 某神犇的板子

轮廓线维护(m+1)个插头状态

4进制(更方便)维护括号表示法:${#,(,)}={0,1,2}$

在代码中有注释

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
#define W 200005
int n,m,tx,ty,pk,nk,B[25];
int cnt[2],hd[W],nxt[W],s[2][W];
ll f[2][W],ans;
char q[15][15];
void ins(int S,ll v){//hash表存状态
    int p=S%W;
    for(int i=hd[p];i;i=nxt[i])
        if(s[nk][i]==S){f[nk][i]+=v; return;}
    nxt[++cnt[nk]]=hd[p]; hd[p]=cnt[nk];
    s[nk][cnt[nk]]=S; f[nk][cnt[nk]]=v;
}
inline int id(int x){return 1<<B[x];}
void work(){
    f[nk][1]=cnt[nk]=1;
    for(int i=1,j,k,u,t;i<=n;++i){
        for(j=1;j<=cnt[nk];++j) s[nk][j]<<=2;//移去旧插头,加入新插头
        for(j=1;j<=m;++j){
            memset(hd,0,sizeof(hd)); pk=nk; nk^=1; cnt[nk]=0;//滚动数组优化
            for(k=1;k<=cnt[pk];++k){
                int S=s[pk][k]; ll v=f[pk][k];
                int R=(S>>B[j-1])%4,D=(S>>B[j])%4;//R:右插头,D:上插头
                if(q[i][j]=='*'){if(!R&&!D)ins(S,v); continue;}
                if(!R&&!D&&j<m) ins(S+id(j-1)+id(j)*2,v);
                if(R&&!D){if(j<m)ins(S-R*id(j-1)+R*id(j),v); ins(S,v);} 
                if(!R&&D){if(j<m)ins(S,v); ins(S+D*id(j-1)-D*id(j),v);}
                if(R==1&&D==1) for(u=j+1,t=1;u<=m;++u){
                    if((S>>B[u])%4==1) ++t;
                    if((S>>B[u])%4==2) --t;
                    if(!t){ins(S-id(j-1)-id(j)-id(u),v); break;}
                }
                if(R==2&&D==2) for(u=j-2,t=1;u>=0;--u){
                    if((S>>B[u])%4==1) --t;
                    if((S>>B[u])%4==2) ++t;
                    if(!t){ins(S-id(j-1)*2-id(j)*2+id(u),v); break;}
                }
                if(R==2&&D==1) ins(S-id(j-1)*2-id(j),v);
                if(R==1&&D==2&&S==id(j-1)+id(j)*2&&i==tx&&j==ty) ans=v;//答案在最后一个非障碍格
            }//各种分类讨论
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=20;++i) B[i]=i<<1;
    for(int i=1;i<=n;++i){
        scanf("%s",q[i]+1);
        for(int j=1;j<=m;++j) if(q[i][j]=='.') tx=i,ty=j;
    }work(); printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/kafuuchino/p/11469721.html