hdu4804 Campus Design

http://acm.hdu.edu.cn/showproblem.php?pid=4804

其实这种放骨牌的题好像也可以直接状压,不过挺难受的,还不如直接插头DP

轮廓线只需要用1和0来标记是否有拓展到右边或下边的1*2骨牌,然后再把已经放了的1*1压进状态里,及bit+=num*mi[m+1]就行了

注意一个细节,当你选择横着放的1*2的骨牌时,由于影响的是下一个位置,需要判断一下是否下一个位置被从上一行往下的骨牌给覆盖了。

转移就是如果当前格子被左边或者右边或者本身就不能放的话,直接把j-1和第j位变成0转移

否则说明当前格子需要放一个新的,考虑放竖的横的和单独放

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=110;
const int mod=1e9+7;
const int hs=1423333;

int n,m,now,cnt[2],mt,C,D;ll ans;
int q[2][hs+3],hd[hs+3],nxt[hs+3],mark[hs+3],mi[20];
ll dp[2][hs+3];
int a[maxl][maxl];
char s[maxl];

inline void prework()
{
	scanf("%d%d",&C,&D);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for(int j=1;j<=m;j++)
			a[i][j]=s[j]-'0';
	}
	for(int j=1;j<=m;j++)
		a[n+1][j]=0;
	for(int i=1;i<=n;i++)
		a[i][m+1]=0;
}

inline void insert(int bit,ll val)
{
	int u=bit%hs+1;
	if(mark[u]!=mt)
		hd[u]=0,mark[u]=mt;
	for(int i=hd[u];i;i=nxt[i])
	if(q[now][i]==bit)
	{
		dp[now][i]=(dp[now][i]+val)%mod;
		return;
	}
	nxt[++cnt[now]]=hd[u];
	hd[u]=cnt[now];
	q[now][cnt[now]]=bit;
	dp[now][cnt[now]]=val; 
}

inline void mainwork()
{
	int num,bit,nbit;ll val;ans=0;
	cnt[now]=1;q[now][1]=0;dp[now][1]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=cnt[now];j++)
		{
			num=q[now][j]>>(m+1);
			q[now][j]&=mi[m+1]-1; 
			q[now][j]*=2;
			q[now][j]+=num*mi[m+1];
		}
		for(int j=1;j<=m;j++)
		{
			now^=1;++mt;cnt[now]=0;
			for(int k=1;k<=cnt[now^1];k++)
			{
				bit=q[now^1][k];num=bit>>(m+1);val=dp[now^1][k];
				if(!a[i][j] || ((bit>>j)&1) || ((bit>>(j-1))&1))
				{	
					nbit=bit;
					if((bit>>j)&1) nbit^=mi[j];
					if((bit>>(j-1))&1) nbit^=mi[j-1];
					insert(nbit,val);
					if(i==n && j==m && C<=num && num<=D)
						ans=(ans+val)%mod;
				}
				else 
				{
					if(a[i][j+1] && !(bit>>(j+1)&1) && j<m)
						insert(bit^mi[j],val);
					if(a[i+1][j] && i<n)
						insert(bit^mi[j-1],val);
					if(num<D)
					{
						insert(bit+mi[m+1],val);
						if(i==n && j==m && C<=num+1 && num+1<=D)
							ans=(ans+val)%mod;
					}
				}
			}	
		}
	}
} 

inline void print()
{
	printf("%lld\n",ans);
}

int main()
{
	mi[0]=1;
	for(int i=1;i<=17;i++)
		mi[i]=mi[i-1]<<1;
	while(~scanf("%d%d",&n,&m))
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/108210314
今日推荐