插头DP

Posted segmenttree

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了插头DP相关的知识,希望对你有一定的参考价值。

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=12;
const int M=1595323;
const int mod=500009;
int n,m,mp[N+5][N+5];
int p3[N+5],now=0,ex,ey;
ll ans;
int ch(char x){return x==‘*‘||x==‘.‘;}
struct Hash
{
	int mak[M],E;
	ll dp[M];
	int h[mod],nxt[M];
	void clear()
	{
		for(int i=0;i<mod;i++) h[i]=0;
		E=0;
		return;
	}
	void add(int pos,ll d)
	{
		int g=pos%mod;
		for(int i=h[g];i;i=nxt[i])
		{
			if(mak[i]==pos)
			{
				dp[i]+=d;
				return;
			}
		}
		E++;
		mak[E]=pos;
		dp[E]=d;
		nxt[E]=h[g];
		h[g]=E;
		return;
	}	
}D[2];
int get(int pos,int x)
{
	pos/=p3[x];
	return pos%3;
}
void cha(int &pos,int x,int t)
{
	int b=get(pos,x);
	pos-=p3[x]*b;
	pos+=p3[x]*t;
	return;
}
void tcol()
{
	D[now].clear();
	for(int i=1;i<=D[now^1].E;i++)
	{
		int mas=D[now^1].mak[i];
		ll dp=D[now^1].dp[i];
		int b=get(mas,m);
		if(!b) D[now].add(mas*3,dp);
	}
	return;
}
void up1(int x,int y)
{
	D[now].clear();
	for(int i=1;i<=D[now^1].E;i++)
	{
		int mas=D[now^1].mak[i];
		ll dp=D[now^1].dp[i];
		int b1=get(mas,y-1),b2=get(mas,y);
		if(!b1&&!b2) D[now].add(mas,dp);
	}
	return;
}
int f1(int mas,int x)
{
	vector<int> s;
	for(int i=0;i<=m;i++)
	{
		s.push_back(mas%3);
		mas/=3;
	}
	int d=0;
	for(int i=x;i<=m;i++) 
	{
		if(s[i]==1) d++;
		if(s[i]==2) d--;
		if(d==0) return i;
	}
	return -1;
}
int f2(int mas,int x)
{
	vector<int> s;
	for(int i=0;i<=m;i++)
	{
		s.push_back(mas%3);
		mas/=3;
	}
	int d=0;
	for(int i=x;i>=0;i--) 
	{
		if(s[i]==1) d++;
		if(s[i]==2) d--;
		if(d==0) return i;
	}
	return -1;
}
void up2(int x,int y)
{
	D[now].clear();
	for(int i=1;i<=D[now^1].E;i++)
	{
		int mas=D[now^1].mak[i];
		ll dp=D[now^1].dp[i];
		int b1=get(mas,y-1),b2=get(mas,y);
		if(!b1&&!b2) 
		{
			cha(mas,y-1,1);
			cha(mas,y,2);
			D[now].add(mas,dp);
		}
		else if(!b1&&b2)
		{
			D[now].add(mas,dp);
			cha(mas,y,0);
			cha(mas,y-1,b2);
			D[now].add(mas,dp);
		}
		else if(b1&&!b2)
		{
			D[now].add(mas,dp);
			cha(mas,y-1,0);
			cha(mas,y,b1);
			D[now].add(mas,dp);
		}
		else if(b1==b2)
		{
			if(b1==1&&b2==1) 
			{
				int d1=f1(mas,y);
				cha(mas,y-1,0);
				cha(mas,y,0);
				cha(mas,d1,1);
				D[now].add(mas,dp);
			}
			else
			{
				int d2=f2(mas,y-1);
				cha(mas,y-1,0);
				cha(mas,y,0);
				cha(mas,d2,2);
				D[now].add(mas,dp);				
			}
		}
		else if(b1==2&&b2==1)
		{
			cha(mas,y-1,0);
			cha(mas,y,0);
			D[now].add(mas,dp);
		}			
		else if(x==ex&&y==ey)
		{
			cha(mas,y-1,0),cha(mas,y,0);
			if(mas==0) ans+=dp;
		}
	}
	return;
}
int main()
{
	p3[0]=1;
	for(int i=1;i<=N+1;i++) p3[i]=p3[i-1]*3;
	scanf("%d%d",&n,&m);
	char w;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			while(!ch(w=getchar()));
			mp[i][j]=w==‘*‘?1:0;
			if(!mp[i][j]) ex=i,ey=j;
		}
	}
	D[0].add(0,1);
	for(int i=1;i<=n;i++)
	{
		now^=1;
		tcol();
		for(int j=1;j<=m;j++)
		{
			now^=1;
			if(mp[i][j]) up1(i,j);
			else up2(i,j);
		}
	}
	printf("%lld
",ans);
	return 0;
}

以上是关于插头DP的主要内容,如果未能解决你的问题,请参考以下文章

HDU4084 插头dp

插头dp

无聊的 邮递员 插头dp

HDU 1693 Eat the Trees (插头DP)

P5056 模板插头dp

插头DP