題面複製於洛谷
鋪設完成後,客廳裡面所有沒有柱子的地方都必須鋪上地板,但同乙個地方不能被鋪多次。
輸入格式:
輸入的第一行包含兩個整數,r和c,表示客廳的大小。接著是r行,每行c個字元。'_'表示對應的位置是空的,必須鋪地板;'*'表示對應的位置有柱子,不能鋪地板。
輸出格式:
輸出一行,包含乙個整數,表示鋪滿整個客廳的方案數。由於這個數可能很大,只需輸出它除以20110520的餘數。
輸入樣例#1:
2 2輸出樣例#1:*___
1輸入樣例#2:
3 3輸出樣例#2:____*_
___
8
參考了:
我終於可以告別插頭dp啦233333……
這道題的難點在於將插頭dp的插頭的定義進行修改。
0:無插頭
1:有插頭且當前格仔所在的地板能再轉彎。
2:有插頭且當前格仔所在的地板不能再轉彎。
有了這些就可以按照插頭dp的思想進行分情況討論了:
(摘自參考部落格)
1.00-->22 或 10 或 01最終把所有情況列舉累加即可。2.11-->00
3.10-->20 或 01
20-->00 或 02
4.01-->10 或 02
02-->00 或 20
ps:第二種情況的11轉換成了00實質上是11相交的地方變成了這塊地板的轉折點(也可以理解為兩塊地板並在了一起)。
#include#include#include
using
namespace
std;
typedef
long
long
ll;const
int inf=2147483647
;const
int mod=300000
;const
int m=1000005
;const
int p=20110520
;struct
nodeedge[m];
inthead[m],cnt;
intn,m;
bool mp[105][105
];int
cur,pre;
int state[2
][m];
ll ans[
2][m],cntt;
int tot[2
];int bit[15
];inline
void
getbit()
inline
void add(int u,int
v)void insert(int
now,ll num)
}add(u,++tot[cur]);
state[cur][tot[cur]]=now;
ans[cur][tot[cur]]=num%p;
return;}
void
plugdp()
for(int j=1;j<=m;j++)
else
if(!is_down&&!is_right)
else
if(is_down&&!is_right)
else
}else
if(!is_down&&is_right)
else
}else
if(is_down==1&&is_right==1
) insert(now-(1
<1])-(1
}for(int k=1;k<=tot[cur];k++)cntt+=ans[cur][k];
return;}
intmain()}}
else}}
plugdp();
printf(
"%lld\n
",cntt);
return0;
}
P2331 SCOI2005 最大子矩陣
這裡有乙個n m的矩陣,請你選出其中k個子矩陣,使得這個k個子矩陣分值之和最大。注意 選出的k個子矩陣不能相互重疊。其中 1 le n le 100,1 le m le 2,1 le k le 10.m 只有 1 和 2 兩種取值,所以直接討論就好 m 1 時 是前 k 個最大連續欄位和 定義 f ...
P2331 SCOI2005 最大子矩陣
傳送門 首先感謝ccsc友 xi 好 zhi 的講解 康康m的範圍 m只能取1或者2 先看m 1 是一條鏈 那麼對於第i個點有三種情況 1 和上面連在一起成乙個矩陣 2 和下面連在一起成乙個矩陣 3 成為斷點 同樣的 對於m 2我們也這樣分析 設f i j k 代表第i行取了j個矩陣屬於第k種情況 ...
2331 SCOI2011 地板 插頭DP
國際慣例的題面 十分顯然的插頭dp。由於r c 100,所以min r,c 10,然後就可以愉悅地狀壓啦。我們用三進製狀壓,0表示沒有插頭,1表示有乙個必須延伸至少一格且拐彎的插頭,2表示有乙個必須延伸一格且不可以拐彎的插頭。轉移的話就十分顯然了。00 22,表示用這個格仔作為開始的拐角。00 10...