p1437 敲磚塊
很自然地,看到這道題我們會想到數字三角形。可惜的是,我們發現:不能簡單地將乙個點的左上角與右上角的值進行比較,因為選擇數可能會有重疊。
不妨畫畫圖,看看我們選擇的是怎樣乙個圖形把。
*****
****
*****
*
比如上面這個東西。
#####
####
#*#**
*
我們發現,選擇的數永遠是若干個三角的重疊。我們考慮按照這個輪廓進行轉移。令 sum
(i,j
)sum(i,j)
sum(i,
j)表示以 (i,
j)
(i,j)
(i,j
) 為左下角的一條斜線的值的和,而 cnt
(i,j
)cnt(i,j)
cnt(i,
j)則表示個數。 f(i
,j,k
)f(i,j,k)
f(i,j,
k)表示選擇到 (i,
j)
(i,j)
(i,j
) ,選擇了 k
kk 個的最大和。則有f(i
,j,k
)←f(
i+1,
j−1,
k)
f(i,j,k)\gets f(i+1,j-1,k)
f(i,j,
k)←f
(i+1
,j−1
,k)f(i
,j,k
)←f(
i−1,
j,k−
cnt(
i,j)
)+su
m(i,
j)
f(i,j,k)\gets f(i-1,j,k-cnt(i,j))+sum(i,j)
f(i,j,
k)←f
(i−1
,j,k
−cnt
(i,j
))+s
um(i
,j)注意邊界,注意初值。
#include
#include
#include
using
namespace std;
typedef
long
long ll;
char in[
1<<20]
,*ss = in,
*tt = in;
#define getchar() (ss == tt && (tt = (ss = in) + fread(in, 1, 1 << 20, stdin), ss == tt) ? eof : *ss++)
ll read()
const
int maxn =55;
const
int maxm =
2505
;const
int pinf =
0xc1c1c1c1
;int n, m, a[maxn]
[maxn]
;int sum[maxn]
[maxn]
, cnt[maxn]
[maxn]
;int f[maxn]
[maxn]
[maxm]
;int
main()
}int ans =0;
for(
int k =
0; k <= m; k++
) ans =
max(ans, f[0]
[n+1
][k]);
printf
("%d\n"
, ans)
;return0;
}
HNOI 2004 敲磚塊 解題報告
hnoi2004 敲磚塊 一道dp題,把其看成乙個直角三角形,敲第 i 列的第j塊時,第i 1列至少是敲了j 1 塊的 s i j k 是敲掉第 i 列第 j塊一共敲了 k 塊的最大分值,那麼轉移方程為 s i j k max s i 1 h k j j 1 h n i h 1 ja h i 時間複...
HNOI2004 打鼴鼠 解題報告
這個題一上來就想到了是o m2 的dp,但是沒有想到優化,導致跑得比較慢。當然其實對於這個題而言優化有無是無所謂的,但是這個優化的思想還是很好的。我一開始是想得用前面的去更新後面的,而如果我們反著來想的話,就可以發現乙個優化了。設f i 表示最後到i可以取得的最大數量,那麼顯然有方程fi max 這...
洛谷 P1437 HNOI2004 敲磚塊
在乙個凹槽中放置了 n 層磚塊 最上面的一層有n 塊磚,從上到下每層依次減少一塊磚。每塊磚 都有乙個分值,敲掉這塊磚就能得到相應的分值,如下圖所示。14 15 4 3 23 33 33 76 2 2 13 11 22 23 31如果你想敲掉第 i 層的第j 塊磚的話,若i 1,你可以直接敲掉它 若i...