USACO16OPEN 248

Posted wxl-ezio

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\)掉了

但是,这样其实还是不对的,因为无法保证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;

以上是关于USACO16OPEN 248的主要内容,如果未能解决你的问题,请参考以下文章

[luoguP3146] [USACO16OPEN]248(区间DP)

luogu3146 [USACO16OPEN]248

P3146 [USACO16OPEN]248

[DP 区间 转移限制] P3146 [USACO16OPEN]248 G

USACO16OPEN 248

luogu P3146 [USACO16OPEN]248