Educational Codeforces Round 59 (Rated for Div. 2) E 区间dp + 状态定义 + dp预处理(分步dp)

https://codeforces.com/contest/1107/problem/E

题意

给出01字符串s(n<=100),相邻且相同的字符可以同时消去,一次性消去i个字符的分数是\(a[i]\),问消去s最多能得到多少分数

题解

  • 实质是安排消去次序使得分数最大,第一步采取的行动是递归边界
  • 因为只有01串,所以s被分成了一段一段,考虑段处理
  • 预处理出一次性消去i个字符的最大分数\(f[i]\)
  • 定义\(dp[l][r][cnt]\)为消去第l到第r段加上cnt个字符和第l段相同得到的最大分数
  • 每个区间只考虑第l段消去的情况(立刻消去or和后面的一起消去)
ans=dfs(l+1,r,0)+f[cnt+b[l]];  //立刻消去第l段
for(int i=l+2;i<=r;i+=2){
    ans=max(ans,dfs(l+1,i-1,0)+dfs(i,r,b[l]+cnt)); //枚举第二段的分割点,dfs(第二段)+dfs(第l段+第三段)
}

代码

#include<bits/stdc++.h>
#define ll long long 
#define MAXN 105
using namespace std;
ll f[MAXN],dp[MAXN][MAXN][MAXN],a[MAXN];
vector<int>b;
string s;
int n,cnt=0;
ll dfs(int l,int r,int cnt){
    if(l>r)return f[cnt];
    ll &ans=dp[l][r][cnt];
    if(ans!=-1)return ans;
    ans=dfs(l+1,r,0)+f[cnt+b[l]];
    for(int i=l+2;i<=r;i+=2)
        ans=max(ans,dfs(l+1,i-1,0)+dfs(i,r,b[l]+cnt));
    return ans;
}
int main(){
    cin>>n>>s;
    for(int i=1;i<=n;i++)cin>>a[i];
    f[1]=a[1];
    for(int i=2;i<=n;i++){
        f[i]=a[i];
        for(int j=1;j<i;j++)
            f[i]=max(f[i],f[j]+f[i-j]);
    }
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<n;i++){
        if(i==0||s[i]==s[i-1])cnt++;
        else{
            b.push_back(cnt);
            cnt=1;
        }
    }
    b.push_back(cnt);
    cout<<dfs(0,b.size()-1,0);
}

猜你喜欢

转载自www.cnblogs.com/VIrtu0s0/p/10808744.html