CF 1107 E. Vasya and Binary String

E. Vasya and Binary String

链接

分析:

  对于长度为x的一段序列,我们可以dp出消除的过程的最优方案,背包即可。

  然后区间dp,可以先合并完所有的点,即没相同的一段区间合并为一个点。设f[i][j][k]表示消完区间[i,j]和这段区间后面k个元素最大值,其中k个元素的颜色与点j的颜色相同。

  转移:可以首先将j和后面k个元素消除,然后消除[i,j-1]。也可以枚举一个和j颜色相同的点m,然后分别先消除[m+1,r-1],剩下的区间就和后面k个连在一起了,再求出这段区间的答案。

  复杂度$O(n^4)$,但是跑不满,再记忆化一下,31ms。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 105;
int n, cnt;
LL a[N], f[N], g[N][N][N];
char s[N];
struct Node { int size, col; } b[N];

void init() {
    for (int i = 1; i <= n; ++i)
        for (int j = i; j <= n; ++j) f[j] = max(f[j], f[j - i] + a[i]);
    int now = 1;
    for (int i = 2; i <= n; ++i) {
        if (s[i] == s[i - 1]) now ++;
        else cnt ++, b[cnt].size = now, b[cnt].col = s[i - 1] - '0', now = 1;
    }
    ++cnt; b[cnt].size = now, b[cnt].col = s[n] - '0';    
}
LL DP(int l,int r,int k) {
    if (l == r) return f[b[l].size + k];
    if (~g[l][r][k]) return g[l][r][k];
    LL res = DP(l, r - 1, 0) + f[b[r].size + k];
    for (int i = l; i < r - 1; ++i) 
        if (b[i].col == b[r].col) res = max(res, DP(i + 1, r - 1, 0) + DP(l, i, b[r].size + k));
    return g[l][r][k] = res;    
}
int main() {
    n = read();
    scanf("%s", s + 1);
    for (int i = 1; i <= n; ++i) a[i] = read(); 
    init();
    memset(g, -1, sizeof(g));
    cout << DP(1, cnt, 0);
    return 0;
}

 

posted @ 2019-03-10 22:08  MJT12044  阅读(237)  评论(0编辑  收藏  举报