[bzoj1210][HNOI2004] Postman [plug dp]

[Question link]
  https://www.lydsy.com/JudgeOnline/problem.php?id=1210
[Question solution]
  An introductory question for plug dp.
  Roughly speaking, it is from top to bottom, from left to right, one grid and one grid dp, and the connectivity with the unsearched grid is recorded by the method of state compression (minimal notation or bracket method).
  For details, see Chen Danqi's: "Dynamic Programming Problems Based on Connectivity State Compression"
  Time Complexity O ( N M 2 2 ( M + 1 ) ) Actually far from it.
  

/* --------------
    user Vanisher
    problem bzoj-1210
----------------*/
# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
using namespace std;
int read(){
    int tmp=0, fh=1; char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    return tmp*fh;
}
const int L=21, N=110,T=(1<<22);
struct INT{
    int num[N],len;
    void reget(){
        int i;
        for (i=1; i<=len||num[i]!=0; i++)
            num[i+1]+=num[i]/10, num[i]=num[i]%10;
        len=i-1;
    }
    void tonum(char *s){
        len=strlen(s+1);
        for (int i=1; i<=len; i++) num[len-i+1]=s[i]-'0';
    }
    void operator =(int tmp){
        memset(this->num,0,sizeof(this->num));
        this->len=0;
        while (tmp!=0) 
            this->num[++(this->len)]=tmp%10, tmp/=10;
    }
    INT operator +(INT b){
        INT c=*this; int i; c.len=max(c.len,b.len);
        for (i=1; i<=c.len; i++) c.num[i]=c.num[i]+b.num[i];
        c.reget(); return c;
    }
    INT operator *(INT b){
        INT c; c.len=b.len+len-1; int i,j;
        memset(c.num,0,sizeof(c.num));
        for (i=1; i<=len; i++)  
            for (j=1; j<=b.len; j++)
                c.num[i+j-1]=c.num[i+j-1]+num[i]*b.num[j];
        c.reget(); return c;
    }
    INT operator *(int tmp){ INT b; b=tmp; return ((*this)*b);}
    INT operator +(int tmp){ INT b; b=tmp; return ((*this)+b);}
    void read(){ char s[N]; scanf("%s",s+1); tonum(s); }
    void print(){
        if (len==0){ printf("0\n"); return; }
        for (int i=len; i>=1; i--) printf("%d",num[i]);
        printf("\n");
    }
}one,ans;
vector <INT> f[2];
vector <int> g[2];
int n,m,now[N],nex[N],f1,f2,lim,h[T],p[T],id;
int getnum(){
    int num=0;
    for (int i=0; i<m+1; i++)
        num=num+(nex[i]<<(i*2));
    return num;
} 
void join(INT num){
    int tmp=getnum();
    if (h[tmp]==-1){
        h[tmp]=f[f2].size();
        p[f[f2].size()]=tmp;
        f[f2].push_back(num);
        g[f2].push_back(tmp);
    }
    else f[f2][h[tmp]]=f[f2][h[tmp]]+num;
}
int main(){
    n=read(), m=read();
    if (n==1||m==1){
        printf("1\n");
        return 0;
    }
    if (n<m) swap(n,m);
    one=1;
    f1=0, f2=1, lim=(1<<((m+1)*2));
    f[f1].push_back(one); 
    g[f1].push_back(1+(2<<(1*2)));
    memset(h,-1,sizeof(h));
    for (int i=0; i<n; i++){
        for (int j=0; j<m; j++){
            if (i==0&&j==0) continue;
            for (unsigned k=0; k<g[f1].size(); k++) h[p[k]]=-1;
            for (unsigned k=0; k<g[f1].size(); k++){
                if (g[f1][k]>=lim) continue;
                INT num=f[f1][k];
                for (int t=0; t<m+1; t++)
                    now[t]=nex[t]=(g[f1][k]>>(t*2))&3;
                if (now[j]!=0&&now[j+1]!=0){
                    if (now[j]==1&&now[j+1]==2&&i==n-1&&j==m-1) 
                        if (g[f1][k]-(now[j]<<(j*2))-(now[j+1]<<(j*2+2))==0)
                            ans=ans+num;
                    if (now[j]==2&&now[j+1]==1) 
                        nex[j]=0, nex[j+1]=0, join(num);
                    if (now[j]==2&&now[j+1]==2){
                        nex[j]=0, nex[j+1]=0;
                        int t=j-1, cnt=0;
                        while (!(cnt==0&&now[t]==1)){
                            if (now[t]==1) cnt--;
                            if (now[t]==2) cnt++;
                            t--;
                        }
                        nex[t]=2; join(num);
                    }
                    if (now[j]==1&&now[j+1]==1){
                        nex[j]=0, nex[j+1]=0;
                        int t=j+2, cnt=0;
                        while (!(cnt==0&&now[t]==2)){
                            if (now[t]==2) cnt--;
                            if (now[t]==1) cnt++;
                            t++;
                        }
                        nex[t]=1; join(num);
                    }
                }
                if (now[j]==0&&now[j+1]!=0){
                    nex[j]=0, nex[j+1]=now[j+1]; join(num);
                    nex[j]=now[j+1], nex[j+1]=0; join(num);
                }
                if (now[j]!=0&&now[j+1]==0){
                    nex[j]=0, nex[j+1]=now[j]; join(num);
                    nex[j]=now[j], nex[j+1]=0; join(num);
                }
                if (now[j]==0&&now[j+1]==0){
                    nex[j]=1, nex[j+1]=2; join(num);
                }   
            }
            swap(f1,f2);
            g[f2].clear(); f[f2].clear();
        }
        for (unsigned k=0; k<g[f1].size(); k++) g[f1][k]=g[f1][k]<<2;
    }
    ans=ans*2;
    ans.print();
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324493530&siteId=291194637