USACO16OPEN 248

题目传送门

比较坑的区间\(DP\)


定义f[i][j]为将i~j这段区间全都合并为一个数的最大值

于是我很自然的就想到了这样转移:

f[i][j] = max(f[i][j], max(f[i][k], f[k+1][j]));
if(f[i][k] == f[k+1][j]) f[i][j] = max(f[i][j], f[i][k] + 1);

但是,因为f[i][k]f[k+1][j]的最大值可能并不相邻,所以第一个转移是不对的,应该只有

if(f[i][k] == f[k+1][j]) f[i][j] = max(f[i][j], f[i][k] + 1);

这样就可以把这道题\(A\)掉了

但是,这样其实还是不对的,能\(A\)是因为数据水,因为无法保证f[i][k]一定能被合成为它表示的数,所以还要标记一下它是否能合成为一个数

if(f[i][k] == f[k + 1][j] && f[i][k] != -1) f[i][j] = max(f[i][j], f[i][k] + 1);

所以最终代码是

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
        k = k * 10 + c - 48, c = getchar();
    return k * f;
}
char read_c() {
    char c = getchar();
    while(c != 'M' && c != 'C') c = getchar();
    return c;
}
int f[250][250], ans;
int main() {
    int n = read(); memset(f, -1, sizeof(f));
    for(int i = 1; i <= n; ++i)
        f[i][i] = read(), ans = max(f[i][i], ans);
    for(int i = n-1; i >= 1; --i)
        for(int j = i+1; j <= n; ++j) {
            for(int k = i; k < j; ++k) {
                if(f[i][k] == f[k+1][j] && f[i][k] != -1) f[i][j] = max(f[i][j], f[i][k] + 1);
                ans = max(f[i][j], ans);
            }
        }
    cout << ans;
    return 0;
}
posted @ 2019-11-14 10:37  MorsLin  阅读(68)  评论(0编辑  收藏  举报