1. 程式人生 > >bzoj2331 [SCOI2011]地板

bzoj2331 [SCOI2011]地板

ret 包含 個數 con out name cli 地板 open

Description

lxhgww的小名叫“小L”,這是因為他總是很喜歡L型的東西。小L家的客廳是一個技術分享的矩形,現在他想用L型的地板來鋪滿整個客廳,客廳裏有些位置有柱子,不能鋪地板。現在小L想知道,用L型的地板鋪滿整個客廳有多少種不同的方案?

需要註意的是,如下圖所示,L型地板的兩端長度可以任意變化,但不能長度為0。鋪設完成後,客廳裏面所有沒有柱子的地方都必須鋪上地板,但同一個地方不能被鋪多次。

技術分享

Input

輸入的第一行包含兩個整數,R和C,表示客廳的大小。

接著是R行,每行C個字符。’_’表示對應的位置是空的,必須鋪地板;’*’表示對應的位置有柱子,不能鋪地板。

Output

輸出一行,包含一個整數,表示鋪滿整個客廳的方案數。由於這個數可能很大,只需輸出它除以20110520的余數。

Sample Input

2 2
*_
__

Sample Output

1

HINT

R*C<=100

正解:插頭$dp$。

插頭$dp$第一題,寫了巨久。。

這道題還是比較裸的,我們把輪廓線的狀態分為$3$種情況,沒有插頭,插頭沒拐彎,插頭已經拐過彎了,然後就很好轉移了。

在每一行的最後一個格子轉移的時候要特判。輪廓線到下一行要左移一位。註意用$4$進制比$3$進制常數更小,$4$進制狀態較大,所以要手寫$hash$。

 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 #define RG register
 4 #define il inline
 5 #define M (1<<22)
 6 #define rhl (20110520)
 7 #define w(s,p) ((s)>>((p)<<1)&3)
 8 #define upd(s,p,v) ((s)^(w(s,p)<<((p)<<1))^((v)<<((p)<<1)))
 9
10 using namespace std; 11 12 int vis[M],S[2][M],f[2][M],sz[M],g[110][110],n,m,pre,cur,ans; 13 14 il char gc(){ 15 RG char ch=getchar(); 16 while (ch!=* && ch!=_) ch=getchar(); return ch; 17 } 18 19 il void add(RG int s,RG int v){ 20 if (vis[s]){ 21 f[cur][vis[s]]+=v; 22 if (f[cur][vis[s]]>=rhl) f[cur][vis[s]]-=rhl; 23 return; 24 } 25 vis[s]=++sz[cur],S[cur][sz[cur]]=s,f[cur][sz[cur]]=v; return; 26 } 27 28 int main(){ 29 #ifndef ONLINE_JUDGE 30 freopen("floor.in","r",stdin); 31 freopen("floor.out","w",stdout); 32 #endif 33 cin>>n>>m; 34 for (RG int i=1;i<=n;++i) 35 for (RG int j=1;j<=m;++j) 36 if (n>=m) g[i][j]=gc()==_; else g[j][i]=gc()==_; 37 if (n<m) swap(n,m); sz[0]=f[0][1]=1; 38 for (RG int i=1;i<=n;++i){ 39 for (RG int k=1;k<=sz[cur];++k) (S[cur][k]<<=2)&=(1<<((m+1)<<1))-1; 40 for (RG int j=1;j<=m;++j){ 41 pre=cur,sz[cur^=1]=0; 42 if (!g[i][j]){ 43 for (RG int k=1;k<=sz[pre];++k) 44 if (!w(S[pre][k],j-1) && !w(S[pre][k],j) && f[pre][k]) add(S[pre][k],f[pre][k]); 45 for (RG int k=1;k<=sz[cur];++k) vis[S[cur][k]]=0; continue; 46 } 47 for (RG int k=1,x,y,s,v;k<=sz[pre];++k){ 48 s=S[pre][k],v=f[pre][k]; if (!v) continue; 49 x=w(s,j-1),y=w(s,j); 50 if (!x && !y){ 51 if (g[i][j+1]) add(upd(upd(s,j-1,0),j,1),v); 52 if (g[i+1][j]) add(upd(upd(s,j-1,1),j,0),v); 53 if (g[i][j+1] && g[i+1][j]) add(upd(upd(s,j-1,2),j,2),v); 54 } 55 if (!x && y==1){ 56 if (g[i+1][j]) add(upd(upd(s,j-1,1),j,0),v); 57 if (g[i][j+1]) add(upd(upd(s,j-1,0),j,2),v); 58 } 59 if (x==1 && !y){ 60 if (g[i][j+1]) add(upd(upd(s,j-1,0),j,1),v); 61 if (g[i+1][j]) add(upd(upd(s,j-1,2),j,0),v); 62 } 63 if (!x && y==2){ 64 add(upd(upd(s,j-1,0),j,0),v); 65 if (g[i+1][j]) add(upd(upd(s,j-1,2),j,0),v); 66 } 67 if (x==2 && !y){ 68 add(upd(upd(s,j-1,0),j,0),v); 69 if (g[i][j+1]) add(upd(upd(s,j-1,0),j,2),v); 70 } 71 if (x==1 && y==1) add(upd(upd(s,j-1,0),j,0),v); 72 } 73 for (RG int k=1;k<=sz[cur];++k) vis[S[cur][k]]=0; 74 } 75 } 76 for (RG int i=1;i<=sz[cur];++i) if (!S[cur][i]) ans=f[cur][i]; 77 cout<<ans; return 0; 78 }

bzoj2331 [SCOI2011]地板