zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    bzoj2115: [Wc2011] Xor
    bzoj2844: albus就是要第一个出场
    hdu3949
    bzoj2487: Super Poker II
    bzoj3456: 城市规划
    bzoj3992: [SDOI2015]序列统计
    ubuntu 使用命令行登录oracle
    ubuntu安装docker
    linux查询硬件信息
    ubuntu oracle 环境搭建
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/11469721.html
Copyright © 2011-2022 走看看