windy有 n 條木板需要被粉刷。 每條木板被分為 m 個格仔。 每個格仔要被刷成紅色或藍色。
windy每次粉刷,只能選擇一條木板上一段連續的格仔,然後塗上一種顏色。 每個格仔最多只能被粉刷一次。
如果windy只能粉刷 t 次,他最多能正確粉刷多少格仔?
乙個格仔如果未被粉刷或者被粉刷錯顏色,就算錯誤粉刷。
很容易發現這是一道揹包問題。
我們發現一共有n條木板,每個木板之間沒有關係,所以我們可以想到用分組揹包。
設子狀態$dp[i][j]$代表處理到第i組刷j次最多能粉刷對多少格仔。
有組之間的轉移方程$dp[i][j] = max(dp[i-1][j], dp[i-1][j-k]+val(i,k))$
其中$val(i,k)$代表第i個木板刷k次所能刷對的最多格仔數。
現在考慮如何求出$val(i,k)$。我們發現只有一維次數是肯定不行的,得再加一維代表刷1-j的格仔。
所以我們得到了組內價值的子狀態:$f[i][j][k]$代表刷第i個木板的1-i,刷k次能刷對的最大格仔數,顯然i那一維是可以省略的。
有轉移方程$f[j][k] = max(f[j][k], f[l][k-1]+max(val2(l+1, j, 1), val2(l+1, j, 0)))$,其中$val2(x, y, u)$代表從x到y全部刷u能刷對的最大格仔數。
val2可以用字首和做到。
然後這道題就迎刃而解了。
/*dp[i][j] 代表前 i 個木板,粉刷 j 次可以粉刷正確的次數
dp[i][j] = max(dp[i-1][j], dp[i-1][j-k]+f[m][k]);
這裡又要引入乙個陣列 f
f[i][j] 代表位置從 1 到 i 粉刷 j 次的最大粉刷正確次數
對於每一組 f 都是不一樣的,要從新求
*/#include
#include
#include
using
namespace
std;
intn, m, t;
char s[55
];int dp[55][2510
];int f[55][55
];int sum[55
];int
ans;
intmain()
//因為每個格仔只能被刷一遍,所以每次被刷的次數只會到 m
for (int t = 1; t <= m; t++) }}
for (int t = 1; t <= t; t++) }}
cout
}
洛谷 4158 SCOI2009 粉刷匠
題目描述 windy有 n 條木板需要被粉刷。每條木板被分為 m 個格仔。每個格仔要被刷成紅色或藍色。windy每次粉刷,只能選擇一條木板上一段連續的格仔,然後塗上一種顏色。每個格仔最多只能被粉刷一次。如果windy只能粉刷 t 次,他最多能正確粉刷多少格仔?乙個格仔如果未被粉刷或者被粉刷錯顏色,就...
題解 lg4158 SCOI2009 粉刷匠
給 n 條每條被劃分成 m 個格仔的木板每個格仔刷顏色,每一次刷只能刷一條木板連續的一段,且每乙個格仔最多只能粉刷一次,一共只能刷 t 次,問能夠正確的刷多少格仔.有乙個很顯然的性質,就是一條木板要是要塗就一定會塗滿但baka fpjo顯然沒有注意到這一點 且還有每乙個格仔最多只能粉刷一次 然後就很...
SCOI2009 迷路 題解
恢復內容開始 題目描述 windy 在有向圖中迷路了。該有向圖有 nnn 個節點,windy 從節點 000 出發,他必須恰好在 ttt 時刻到達節點 n 1n 1n 1。現在給出該有向圖,你能告訴 windy 總共有多少種不同的路徑嗎?注意 windy 不能在某個節點逗留,且通過某有向邊的時間嚴格...