【bzoj2331】[SCOI2011]地板 插头dp

插头dp
f[i][j][S]表示转移到第i行第j列轮廓线为S的方案数
0表示没有插头,1表示插头没有拐过弯,2表示插头拐过弯
1、
3进制不好写,写4进制
一共3^11个状态,200000左右
bit[i]=i*2
取出4进制的第i位  (S/(1< 状态的第j位  1< 2、
bfs只记录有用的状态
3、
因为f[i][j]只与f[i][j-1]有关,所以不妨用滚动数组
4、

有下插头的位置正下方必然有上插头


#include
#include
#include
#include
#include
#include
#define maxn 200010
#define mod 20110520

using namespace std;

int a[110][110];
int f[2][maxn],tot[2],hash[2][maxn],head[50010],to[maxn],next[maxn],bit[110];
int n,m,now,pre,num;
char s[110];

void add(int s,int d)
{
	int x=s%50000;
	for (int p=head[x];p;p=next[p])
	  if (hash[now][to[p]]==s)
	  {
	  	f[now][to[p]]=(f[now][to[p]]+d)%mod;
	  	return;
	  }
	tot[now]++;
	hash[now][tot[now]]=s;
	f[now][tot[now]]=d;
	num++;to[num]=tot[now];next[num]=head[x];head[x]=num;
}

void dp()
{
	now=1;pre=0;
	tot[now]=1;
	hash[now][1]=0;
	f[now][1]=1;
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=tot[now];j++) hash[now][j]<<=2;
		for (int j=1;j<=m;j++)
		{
			swap(now,pre);
			tot[now]=0;
			num=0;
			memset(f[now],0,sizeof(f[now]));
			memset(head,0,sizeof(head));
			for (int k=1;k<=tot[pre];k++)
			{
				int s=hash[pre][k],num=f[pre][k];
				if (!num) continue;
				int p=(s/(1<=m)
	{
		for (int i=1;i<=n;i++)
		{
			scanf("%s",s+1);
			for (int j=1;j<=m;j++)
			  if (s[j]=='_') a[i][j]=1; else a[i][j]=0;
		}
	}
	else
	{
		for (int i=1;i<=n;i++)
		{
			scanf("%s",s+1);
			for (int j=1;j<=m;j++)
			  if (s[j]=='_') a[j][i]=1; else a[j][i]=0;
		}
		swap(n,m);
	}
	dp();
	printf("%d\n",f[now][1]);
	return 0;
}


你可能感兴趣的:(动态规划)