4565 Haoi2016 字元合併

2021-07-25 03:01:58 字數 1884 閱讀 4444

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...