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;
}