「UVA10559」Blocks

传送门
Luogu

解题思路

考虑区间 \(\text{DP}\)
\(f[i][j][k]\) 表示 \([i,j]\) 这段区间接上后面 \(k\) 个与 \(j\) 颜色相同的块得到的答案。
转移就是:
\(f[i][j][k] = \max\left\{f[i][j][0]+(k+1)^2\right\}\)
\(f[i][j][k] = \max\left\{f[i][p][k+1]+f[p+1][j-1][0]\right\}(p\in[i, j]\text{且}c_p=c_j)\)
第一个方程就是把后面那一坨一起消掉,再消掉前面。
第二个方程就是在中间找一个与 \(j\) 颜色相同的点 \(p\) ,把 \([p+1,j-1]\) 这段先消掉,然后让剩下的两坨拼起来再消。
写成记搜很方便的说

细节注意事项

  • 咕咕咕

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#define rg register
using namespace std;
template < typename T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while (!isdigit(c)) f |= (c == '-'), c = getchar();
    while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    s = f ? -s : s;
}

const int _ = 202;

int n, a[_], f[_][_][_], pre[_], las[_];

inline int dfs(int i, int j, int k) {
    if (i > j) return 0;
    if (f[i][j][k]) return f[i][j][k];
    f[i][j][k] = max(f[i][j][k], dfs(i, j - 1, 0) + (k + 1) * (k + 1));
    for (rg int p = pre[j]; p >= i; p = pre[p])
        f[i][j][k] = max(f[i][j][k], dfs(i, p, k + 1) + dfs(p + 1, j - 1, 0));
    return f[i][j][k];
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
#endif
    int T; read(T);
    for (rg int o = 1; o <= T; ++o) {
        memset(f, 0, sizeof f);
        memset(pre, 0, sizeof pre);
        memset(las, 0, sizeof las);
        read(n);
        for (rg int i = 1; i <= n; ++i) read(a[i]);
        for (rg int i = 1; i <= n; ++i) pre[i] = las[a[i]], las[a[i]] = i;
        printf("Case %d: %d\n", o, dfs(1, n, 0));
    }
    return 0;
}

完结撒花 \(qwq\)

猜你喜欢

转载自www.cnblogs.com/zsbzsb/p/11746537.html
今日推荐