zoukankan      html  css  js  c++  java
  • 【BZOJ2331】[SCOI2011]地板 插头DP

    【BZOJ2331】[SCOI2011]地板

    Description

    lxhgww的小名叫L”,这是因为他总是很喜欢L型的东西。小L家的客厅是一个的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板。现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案?

    需要注意的是,如下图所示,L型地板的两端长度可以任意变化,但不能长度为0。铺设完成后,客厅里面所有没有柱子的地方都必须铺上地板,但同一个地方不能被铺多次。

    Input

    输入的第一行包含两个整数,RC,表示客厅的大小。

    接着是R行,每行C个字符。’_’表示对应的位置是空的,必须铺地板;’*’表示对应的位置有柱子,不能铺地板。

    Output

    输出一行,包含一个整数,表示铺满整个客厅的方案数。由于这个数可能很大,只需输出它除以20110520的余数。

    Sample Input

    2 2
    *_
    __

    Sample Output

    1

    HINT

    R*C<=100

    题解:我们取R和C中小的那维做状态。显然状态是三维的:对于轮廓线上的每个位置,用0表示无插头,1表示有插头,并且这个L还没有拐弯,2表示有插头,并且L已经拐弯了。然后进行3*3的讨论吧!注意一个拐过弯的插头可以停止,一个没拐过弯的插头可以拐弯。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=177200;
    const int P=20110520;
    int n,m,k,tag,tot;
    char str[110][110];
    int dp[2][maxn],bt[20],m3[maxn];
    inline void upd(int a) {dp[k][a]+=tag;	if(dp[k][a]>=P)	dp[k][a]-=P;}
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int i,j,S,T,p,q,x,y;
    	for(i=1;i<=n;i++)	scanf("%s",str[i]+1);
    	if(n<m)
    	{
    		for(i=1;i<=m;i++)	for(j=1;j<i;j++)	swap(str[i][j],str[j][i]);
    		swap(n,m);
    	}
    	for(i=bt[0]=1;i<=m+1;i++)	bt[i]=bt[i-1]*3;
    	for(tot=bt[m+1],i=1;i<tot;i++)	m3[i]=i%3;
    	dp[0][0]=1;
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=m;j++)
    		{
    			k^=1;
    			memset(dp[k],0,sizeof(dp[k]));
    			for(S=0;S<tot;S++)	if(dp[k^1][S])
    			{
    				x=bt[j-1],y=bt[j],p=m3[S/x],q=m3[S/y],tag=dp[k^1][S],T=S-x*p-y*q;
    				if(str[i][j]=='*')
    				{
    					if(!p&&!q)	upd(T);
    					continue;
    				}
    				if(!p&&!q)
    				{
    					if(i!=n&&j!=m)	upd(T+((x+y)<<1));
    					if(i!=n)	upd(T+x);
    					if(j!=m)	upd(T+y);
    				}
    				if(!p&&q==1)
    				{
    					if(i!=n)	upd(T+x);
    					if(j!=m)	upd(T+(y<<1));
    				}
    				if(!p&&q==2)
    				{
    					if(i!=n)	upd(T+(x<<1));
    					upd(T);
    				}
    				if(!q&&p==1)
    				{
    					if(j!=m)	upd(T+y);
    					if(i!=n)	upd(T+(x<<1));
    				}
    				if(!q&&p==2)
    				{
    					if(j!=m)	upd(T+(y<<1));
    					upd(T);
    				}
    				if(p==1&&q==1)	upd(T);
    			}
    		}
    		for(S=tot-1;S>=0;S--)	dp[k][S]=(m3[S]>0)?0:dp[k][S/3];
    	}
    	printf("%d",dp[k][0]);
    	return 0;
    }//10 10 __________ __________ __________ __________ __________ __________ __________ __________ __________ __________
  • 相关阅读:
    图标库
    AndroidManifest中注册application
    两个App之间的跳转 并传值
    Fresco加载显示gif图片
    弹出PopupWindow背景变暗的实现
    判断网络是否可用
    Java的安全性和可移植性
    DBUtils
    Observer
    IO
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8010802.html
Copyright © 2011-2022 走看看