Plug dp study notes

Because the plug dp is difficult to understand, I came to take notes again
Plug DP can be used to solve some problems. The specific process is to divide the grid, and then roll it as needed to press the contour state. It is usually in hexadecimal (?) Or something.
Take luogu example:

give n*m Some grids cannot be laid, others must be laid to form a closed loop. How many paving methods are there? n,m(2<=n,m<=12)

For this problem, only the plug above the grid and the plug on the left of the grid are considered. Then, for the current contour corner (DP position), B1 and B2 represent the right plug and the lower plug. Then, in Quaternary, for a line segment, 0 represents no plug, 1 represents a left end point (left bracket), 2 represents a right end point (right bracket), and the brackets match each other.
First, if the current grid cannot move, you can only move from the position without b1 and b2:

if(!a[i][j]){
	if(!b1&&!b2){
		ins(bit,num);
	}
}

Then, we will discuss various situations in which the current grid can be divided:

!b1&&!b2

In this case, we need to add two plugs (one left plug and one right plug) to make this point pass.

else if(!b1&&!b2){
	if(a[i+1][j]&&a[i][j+1])
		ins(bit+bin[j-1]+bin[j]*2,num);
}

In the code, the left bracket of line j and the right bracket of j+1 are added.

!b1&&b2

There is only one plug and it is downward, so you can choose to extend the plug downward or to the right:

else if(!b1&&b2){
	if(a[i][j+1])
		ins(bit,num);
	if(a[i+1][j])
		ins(bit-bin[j]*b2+bin[j-1]*b2,num);
}

If it can be extended to the right, it can be extended to the right. If it can be extended downward, first remove the plug of line j+1 and change it to the downward plug of line J.

b1&&!b2

If there is a plug poked horizontally, it can continue to extend to the right or change to downward.

else if(b1&&!b2){
	if(a[i+1][j])
		ins(bit,num);
	if(a[i][j+1])
		ins(bit-bin[j-1]*b1+bin[j]*b1,num);
}

In addition, in the above two cases \ (\ times b1/b2 \) is because it does not change their properties as left or right parentheses.

b1=1&&b2=1

The two left parentheses met and merged. We deleted the two left parentheses, but in order to ensure legality, we changed the original right parenthesis to the left parenthesis.

else if(b1==1&&b2==1){
	int k1=1;
	F(l,j+1,m){
		if(((bit>>(l<<1))&3)==1)
			k1++;
		if(((bit>>(l<<1))&3)==2)
			k1--;
		if(!k1){
			ins(bit-bin[j]-bin[j-1]-bin[l],num);
			break;
		}
	}
}

b1=2&&b2=2

Similar to the above, find the left parenthesis and change it to the right parenthesis.

else if(b1==2&&b2==2){
	int k1=1;
	D(l,j-2,0){
		if(((bit>>(l<<1))&3)==1)
			k1--;
		if(((bit>>(l<<1))&3)==2)
			k1++;
		if(!k1){
			ins(bit-bin[j]*2-bin[j-1]*2+bin[l],num);
			break;
		}
	}
}

b1=2&&b2=1

The two left and right brackets can be deleted directly. Although they are back-to-back, it does not affect them, because there must be other left and right brackets paired.

else if(b1==2&&b2==1){
	ins(bit-bin[j-1]*2-bin[j],num);
}

b1=1&&b2=2

It means that this can be regarded as the end point. If this is the end point, it will be added to the answer, otherwise it will be discarded.

else if(i==ex&&j==ey)ans+=num;

Then these states can handle all situations, and put a full code:

#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	#define int long long
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=15,mod=300000;
	int a[N][N],n,m,ex,ey,bin[N],now,lst,head[mod],next[2<<24],cnt[2],val[2][2<<24],key[2][2<<24];
	inline void ins(int bit,int num){
		ll v=bit%mod;
		for(int i=head[v];i;i=next[i]){
			if(key[now][i]==bit){
				val[now][i]+=num;
				return;
			}
		}next[++cnt[now]]=head[v];
		head[v]=cnt[now];
		val[now][cnt[now]]=num;
		key[now][cnt[now]]=bit;
	}
	inline short main(){
	//	file();
	    std::cout<<std::oct;
		n=read(),m=read();int ans=0;
		F(i,1,n){
			F(j,1,m){
				char ch=getchar();
				while(ch!='*'&&ch!='.')ch=getchar();
				a[i][j]=(ch=='*'?0:1);
				if(a[i][j])ex=i,ey=j;
			}
		}bin[0]=1;
		F(i,1,m)bin[i]=bin[i-1]<<2;
		cnt[now]=1,val[now][1]=1;
		F(i,1,n){
			F(j,1,cnt[now])key[now][j]<<=2;
			F(j,1,m){
				memset(head,0,sizeof(head));
				lst=now,now^=1;
				cnt[now]=0;
				F(k,1,cnt[lst]){
					int bit=key[lst][k],num=val[lst][k];
					int b1=(bit>>((j-1)<<1))&3,b2=(bit>>(j<<1))&3;
					if(!a[i][j]){
						if(!b1&&!b2){
							ins(bit,num);
						}
					}else if(!b1&&!b2){
						if(a[i+1][j]&&a[i][j+1])
							ins(bit+bin[j-1]+bin[j]*2,num);
					}else if(!b1&&b2){
						if(a[i][j+1])
							ins(bit,num);
						if(a[i+1][j])
							ins(bit-bin[j]*b2+bin[j-1]*b2,num);
					}else if(b1&&!b2){
						if(a[i+1][j])
							ins(bit,num);
						if(a[i][j+1])
							ins(bit-bin[j-1]*b1+bin[j]*b1,num);
					}else if(b1==1&&b2==1){
						int k1=1;
						F(l,j+1,m){
							if(((bit>>(l<<1))&3)==1)
								k1++;
							if(((bit>>(l<<1))&3)==2)
								k1--;
							if(!k1){
								ins(bit-bin[j]-bin[j-1]-bin[l],num);
								break;
							}
						}
					}else if(b1==2&&b2==2){
						int k1=1;
						D(l,j-2,0){
							if(((bit>>(l<<1))&3)==1)
								k1--;
							if(((bit>>(l<<1))&3)==2)
								k1++;
							if(!k1){
								ins(bit-bin[j]*2-bin[j-1]*2+bin[l],num);
								break;
							}
						}
					}else if(b1==2&&b2==1){
						ins(bit-bin[j-1]*2-bin[j],num);
					}else if(i==ex&&j==ey)ans+=num;
				}
			}
		}pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

Brush the questions

Added by Or1g1naL on Mon, 10 Jan 2022 08:48:37 +0200