time limit: 20 sec
memory limit: 256 mb
submit: 154
solved: 70 [
submit][
status][
discuss]
有乙個長度為 n 的 01 串,你可以每次將相鄰的 k 個字元合併,得到乙個新的字元並獲得一定分數。得到的新字
符和分數由這 k 個字元確定。你需要求出你能獲得的最大分數。
第一行兩個整數n,k。接下來一行長度為n的01串,表示初始串。接下來2k行,每行乙個字元ci和乙個整數wi,ci
表示長度為k的01串連成二進位制後按從小到大順序得到的第i種合併方案得到的新字元,wi表示對應的第i種方案對應
獲得的分數。1<=n<=300,0<=ci<=1,wi>=1,
k<=8
輸出乙個整數表示答案
3 2101
1 10
1 10
0 20
1 30
40//第3行到第6行表示長度為2的4種01串合併方案。00->1,得10分,01->1得10分,10->0得20分,11->1得30分。 [
submit][
status][
discuss]
區間dp + 狀壓dp,被轉移卡了好久。。暈
設f[i][j][k]:[i,j]內的數碼合併成狀態k的最優方案
合併一段區間,只要兩次操作的數碼位置不重疊,先後順序無影響
那麼每個狀態的k就設定為當前區間進行盡可能多次合併以後的結果
並且轉移時列舉最後一次操作,也就是說每次轉移進行的操作都是發生在當前區間最右端。。
那麼可以寫出這兩個式子
f[i][j][s<<1] = max(f[i][mid-1][s] + f[i][mid][0])
f[i][j][s<<1|1] = max(f[i][mid-1][s] + f[i][mid][1])
特別地,如果當前區間經過上兩個操作後剩餘長度剛好為k,需要額外進行合併轉移
也就是把當前k個數碼壓縮成乙個
用乙個輔助陣列取max即可#include#include#includeusing namespace std;
const int maxn = 303;
typedef long long ll;
const ll inf = 1e12;
ll val[maxn],f[maxn][maxn][maxn];
int n,k,s[maxn],t[maxn];
char ch[maxn];
void pre_work()
{ cin >> n >> k;
scanf("%s",ch + 1);
for (int i = 1; i <= n; i++) s[i] = ch[i] - '0';
for (int i = 0; i < (1for (int op = 0,k = (1<
貌似f陣列轉移取mid位置時得將mid前數碼位數不夠的情況捨去,,不過沒去掉也a了
狀壓dp的話,,人工確定不影響求解的順序能大大優化轉移!!
總複雜度o(n^3*2^k)不過沒理論這麼大。。
4565 Haoi2016 字元合併 區間DP
令fi j,k 表示區間 i j 合併成 k 的最大收益,其中k 0 1保證 i,j 可以合併成乙個數。轉移的時候用gj k表示對於當前的 i i j 合併成了 k 其中 k是乙個二進位制數。然後轉移一下就行了 include include include using namespace std ...
bzoj4565 HAOI2016 字元合併
time limit 20 secmemory limit 256 mb有乙個長度為 n 的 01 串,你可以每次將相鄰的 k 個字元合併,得到乙個新的字元並獲得一定分數。得到的新字 符和分數由這 k 個字元確定。你需要求出你能獲得的最大分數。第一行兩個整數n,k。接下來一行長度為n的01串,表示初...
1767 字元合併
description 有乙個長度為 n 的 01 串,你可以每次將相鄰的 k 個字元合併,得到乙個新的字元並獲得一定分數。得到的新字 符和分數由這 k 個字元確定。你需要求出你能獲得的最大分數。input 第一行兩個整數n,k。接下來一行長度為n的01串,表示初始串。接下來2k行,每行乙個字元ci...