【CF EDU59 E】 Vasya and Binary String (DP)

題意

給一串01串,對該串進行若干次操做,直到串爲空ios

操做爲:選擇一段連續的0或者1,刪除它,拼接先後兩部分紅爲新串,獲得價值爲a[刪除的長度](a爲給定的數組)c++

思路

一個很是規的DP數組

考慮題目所給的操做,咱們從中刪除一段,再把先後拼接起來,如何設置狀態?記錄下斷點的位置?不行,那樣咱們可能在其中插入不少斷點,而且不便於轉移spa

$...111000111...$code

若是咱們僅僅研究中間的子串$111000111$ci

咱們刪除中間的0,造成$111111$it

再刪除中間的1,這樣咱們其實能夠看作原串是$000\underline{111}111$io

也就是前面的1和後面的1實際上是捆在一塊兒的,這樣按原來的操做,答案不會改變class

設置狀態:$dp[i][j][k]​$ 表示刪除從i到j的子串,該子串前面捆綁了$k-1​$個與$s[i]​$相同的字符,能獲得的最大價值搜索

這樣的話,考慮轉移方式:

  1. 咱們直接刪除前面$k$個相等的字符,$dp[i][j][k] = a[k] + dp[i+1][j][1]$,由於捆綁的全消耗掉了因此後半部分是$K = 1$

  2. 咱們從中刪除一段,再把先後粘貼起來,這樣的話,也就是上面的狀況,咱們須要把前面的和後面的捆綁起來,因此必須知足從中找到一個點$mid > i,s[i] = s[mid]$,這樣的話$dp[i][j][k] = dp[i+1][mid-1][1] + dp[mid][j][k+1]$

    看這個式子,咱們只捆綁的是第一個字符,由於咱們能夠屢次進行這樣的操做,使得捆綁的是任意的(這裏不須要咱們本身去構造,而是在求解過程當中天然構造的)

因此最後的答案是$dp[1][n][1]$

因爲這個轉移比較騷,咱們能夠採用記憶化搜索

代碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
char s[105];
ll a[105];
ll dp[105][105][105];
ll DP(int be,int en,int pre) {
    if(be > en) return 0;
    if(dp[be][en][pre]) return dp[be][en][pre];
    if(be == en) return dp[be][en][pre] = a[pre];
    ll ans = a[pre] + DP(be+1,en,1);
    for(int mid = be+1;mid <= en;mid++) {
	if(s[mid] == s[be]) 
    	    ans = max(ans,DP(be+1,mid-1,1) + DP(mid,en,pre+1));
    }
    return dp[be][en][pre] = ans;
} 
int main() {
    ios::sync_with_stdio(false);
    cin>>n;
    cin>>s+1;
    for(int i=1;i<=n;i++) cin>>a[i];
    cout<<DP(1,n,1)<<endl;
}
相關文章
相關標籤/搜索