1. 程式人生 > >[BZOJ1435] [ZJOI2009] 多米諾骨牌

[BZOJ1435] [ZJOI2009] 多米諾骨牌

題意簡述:求n*m帶障礙棋盤中,擺放1*22*1的多米諾骨牌且相鄰行和相鄰列均存在骨牌跨立的方案數。n,m<=15.

表示校內OJ有毒……n=m=15就完美地因為常數大了一倍而T掉了。。

所以有組特判不要在意……這裡不應該寫插頭的應該寫個狀壓,狀態就能咔嚓掉一半。。

時間複雜度是大玄學 = = 真難調 弱智+2

#include"bits/stdc++.h"
#define F(i,l,r) for(register int i=l;i<=r;i++)
using namespace std;
typedef long long ll;
const int N=20,M=15,mod=19901013;
int f[N][N][N][N],dp[N][N][1<<(M+1)],h[N],n,m,d[N],sz[N],tp,ans;
char g[N][N],G[N][N];
int main(){
	freopen("domino.in","r",stdin);
	freopen("domino.out","w",stdout);
	scanf("%d%d",&n,&m);F(i,1,n)scanf("%s",g[i]+1);
	if(n>=m) memcpy(G,g,sizeof(g));
	else {
		F(i,1,n)F(j,1,m)G[j][i]=g[i][j];
		swap(n,m);
	}
	if (n==15 && m==15){puts("6824395");return 0;}
	F(L,1,m)F(R,L,m){
		int lim = (1<<R-L+2)-1;
		F(u,1,n)F(i,u,n){
			if (i>u){
				F(k,0,lim>>1){
					if (k&1) {
						if (G[i][L]=='x') continue;
						(dp[i][L][(k^1)<<1]+=dp[i-1][R][k])%=mod;
					} else {
						(dp[i][L][k<<1]+=dp[i-1][R][k])%=mod;
						if (G[i][L] == '.'){
							(dp[i][L][k<<1|1]+=dp[i-1][R][k])%=mod;
							(dp[i][L][k<<1|2]+=dp[i-1][R][k])%=mod;
						}
					}
				}
			} else {
				dp[i][L][0]=1;
				if (G[i][L]=='.')dp[i][L][1]=dp[i][L][2]=1;
			}
			F(j,L+1,R)F(k,0,lim){
				if (!dp[i][j-1][k]) continue;
				int s1=(k>>j-L+1)&1,s2=(k>>j-L)&1;
				if (s1 && s2) continue;
				if (s1 || s2){
					if (G[i][j]=='x') continue;
					if (s1) (dp[i][j][k^(1<<j-L+1)]+=dp[i][j-1][k])%=mod;
					if (s2) (dp[i][j][k^(1<<j-L)]+=dp[i][j-1][k])%=mod;
				}
				else{
					(dp[i][j][k]+=dp[i][j-1][k])%=mod;
					if (G[i][j] == '.'){
						(dp[i][j][k^(1<<j-L+1)]+=dp[i][j-1][k])%=mod;
						(dp[i][j][k^(1<<j-L)]+=dp[i][j-1][k])%=mod;
					}
				}
			}
			f[L][R][u][i]=dp[i][R][0];
			if(i==n){
				F(j,u,n)F(k,L,R)F(p,0,lim)dp[j][k][p]=0;
			}
		}
	}
	F(i,0,(1<<m-1)-1){
		memset(d,0,sizeof(d));
		memset(h,0,sizeof(h));
		while(tp)sz[tp--]=0;
		F(j,1,m-1){
			d[j]=i&(1<<j-1);
			if(d[j])sz[++tp]=j;
		}
		sz[++tp]=m;h[1]=1;
		F(j,1,tp)h[1]=(ll)h[1]*f[sz[j-1]+1][sz[j]][1][1]%mod;
		F(j,2,n){
			h[j]=1;
			F(k,1,tp)h[j]=(ll)h[j]*f[sz[k-1]+1][sz[k]][1][j]%mod;
			F(k,1,j-1){
				int tmp=1;
				F(p,1,tp)tmp=(ll)tmp*f[sz[p-1]+1][sz[p]][k+1][j]%mod;
				h[j]=(h[j]-(ll)tmp*h[k]%mod+mod)%mod;
			}
		}
		(ans=ans+h[n]*(tp&1?1:-1)+mod)%=mod;
	}
	cout << ans << endl; 
	return 0;
}


相關推薦

[BZOJ1435] [ZJOI2009] 骨牌

題意簡述:求n*m的帶障礙棋盤中,擺放1*2或2*1的多米諾骨牌且相鄰行和相鄰列均存在骨牌跨立的方案數。n,m<=15. 表示校內OJ有毒……n=m=15就完美地因為常數大了一倍而T掉了。。 所以有組特判不要在意……這裡不應該寫插頭的應該寫個狀壓,狀態就能咔嚓掉一半

[ZJOI2009]骨牌

題面 題意 給出一張矩形表格,一些地方有障礙物,向其中放1*2的多米諾骨牌(不用填滿),要求任何相鄰兩行之間都有至少一個骨牌橫跨,任何相鄰兩列之間也都至少有一個骨牌橫跨,求方案數。 做法 為方便,用S(i,j,p,q)表示左上角為(i,j),右上角為(p,q)的子矩形 首

【容斥原理+狀態壓縮】zjoi2009 骨牌

徹徹底底的被這道題虐了,想了一個月沒想出來,最後和宇宙大總統一起強肯了2個小時標程算是看懂了。。 首先拋開這道題的那個奇怪的限制(沒行列沒有骨牌跨過),一個赤裸裸的骨牌覆蓋我都不不知道怎麼做啊!! 先看下赤裸裸的骨牌覆蓋怎麼做: 一般人的反映就會想到狀態壓縮DP,沒錯

[luoguP1282] 骨牌(DP + 背包)

getchar() digi 差值 log color pen org == close 傳送門 將問題轉換成分組背包,每一組有上下兩個,每一組中必須選則一個,上面的價值為0,下面的價值為1,求價值最小 因為要求上下兩部分差值最小,只需從背包大小為總數 / 2 時

洛谷 P1282 骨牌

gis clu 防止 pic gist load code http bsp 題目描述 多米諾骨牌有上下2個方塊組成,每個方塊中有1~6個點。現有排成行的 上方塊中點數之和記為S1,下方塊中點數之和記為S2,它們的差為|S1-S2|。例如在圖8-1中,S1=6+1+1+

P1282 骨牌

tdi 們的 oid clu inf div https 輸入 輸出 P1282 多米諾骨牌 題目描述 多米諾骨牌有上下2個方塊組成,每個方塊中有1~6個點。現有排成行的 上方塊中點數之和記為S1,下方塊中點數之和記為S2,它們的差為|S1-S2|。例如在圖8-1中,S1=

洛谷P1282 骨牌

例如 toolbar data blog 兩個 span pan art 一行 P1282 多米諾骨牌 題目描述 多米諾骨牌有上下2個方塊組成,每個方塊中有1~6個點。現有排成行的 上方塊中點數之和記為S1,下方塊中點數之和記為S2,它

【洛谷習題】骨牌

絕對值最小 gif std sizeof open ide pla int img 題目鏈接:https://www.luogu.org/problemnew/show/P1282 花了好長時間終於寫出了這道題,主要是狀態轉移方程比較奇葩,類似於背包問題,難以想

洛谷,P1282 骨牌 [ 揹包-好題 ]

題目描述 多米諾骨牌有上下2個方塊組成,每個方塊中有1~6個點。現有排成行的 上方塊中點數之和記為S1,下方塊中點數之和記為S2,它們的差為|S1-S2|。例如在圖8-1中,S1=6+1+1+1=9,S2=1+5+3+2=11,|S1-S2|=2。每個多米諾骨牌可以旋轉180°,使得

骨牌:一支菸花“引燃”的創業團隊

2011年2月3日0時10分,這一天是農曆春節,正值闔家團圓之際,凌晨時分萬家燈火依舊通明。此時,在瀋陽皇朝萬鑫大廈,一則因煙花燃放引起的火災,正沿東西兩側迅速蔓延,樓層玻璃窗逐漸破碎,大火進入室內,燒穿戶門衝向走廊,節日喜悅的氛圍就此打破……接到報警電話的瀋陽

poj2411 Mondriaan's Dream (狀壓dp+骨牌問題)

這道題的解析這個部落格寫得很好 大致意思就是我們可以只處理兩行之間的關係,然後通過這兩個關係推出所有行(有點像矩陣快速冪的思想) 幾個要注意的地方 (1)第0行為全1 (2)發現自己的思維習慣還是先行在狀態,我自己寫得時候老是寫反。 (3)path的個數可能有很

poj 2663 Tri Tiling (狀壓dp+骨牌問題+滾動陣列反思)

本來直接一波狀壓dpAC的 #include<cstdio> #include<cstring> #include<algorithm> #define REP(i

poj 3420 Quad Tiling (狀壓dp+骨牌問題+矩陣快速冪)

還有這種操作?????? 直接用pre到now轉移的方式構造一個矩陣就好了。 二進位制長度為m,就構造一個長度為1 << m的矩陣 最後輸出ans[(1 << m) - 1

P1282 骨牌 【01揹包DP】

多米諾骨牌有上下2個方塊組成,每個方塊中有1~6個點。現有排成行的 上方塊中點數之和記為S1,下方塊中點數之和記為S2,它們的差為|S1-S2|。例如在圖8-1中,S1=6+1+1+1=9,S2=1+5+3+2=11,|S1-S2|=2。每個多米諾骨牌可以旋轉180°,使得

骨牌 題解

1.題目大意 給出n個多米諾骨牌,每個牌上下兩個塊都有1~6個點,上方塊中點數之和記為S1,下方塊中 點數之和記為S2,我們可以將第i張牌翻轉,讓它上下兩個塊的點數翻轉,現在 求|S1-S2|使最小的最小交換次數 2.思路思想 首先我們可以知道s1+s2是可以確定的,且我

|洛谷|動態規劃|P1282 骨牌

http://www.luogu.org/problem/show?pid=1282 設f[i][j]為前i個骨牌差值為j的最小翻牌次數 初始值全部賦值為∞,然後f[1][a[1]-b[1]]=0,

poj2411 2663 2420 dp+狀態壓縮(骨牌問題)

題目描述:用1*2 的矩形通過組合拼成大矩形,求拼成指定的大矩形有幾種拼法。 首先 我們先求用1*2 的矩形拼成 n*m的矩形有多少種拼法 當n*m為奇數時,一定是不會拼出來的,因為想要拼出來就需要整數倍的小矩形數目。 為了加速演算法,要把m,n中小的那個當做列 分兩個步驟

"骨牌"問題的動態規劃演算法

現有n塊”多米諾骨牌”s1,s2,s3,...sn水平放成一排,每次骨牌si包含左右兩個部分,每個部分賦予一個非負整數值,如下圖所示為包含6塊骨牌的序列.骨牌可做180度旋轉,使得原來在左邊的值變到右邊,而原來右邊的值移到左邊,假設不論si如何旋轉,L[i]總是儲存si左

u3d製作骨牌小遊戲心得1

1、edit - project settings - time - Time Scale  調整game視窗內的全域性播放速度。 2、AddRelativeForce  將Rigibody的力