Problem’s Website
- 248
Solution
- 这道题是一道区间dp模板题,区间dp,根据名称,我们可以得出是在区间内做dp,一般设$f[i][j]$为左端点为$i$,右端点为$j$是的某一状态,对于这道题来说,$f[i][j]$为把$i$到$j$合并的最大值。
我们首先从大到小枚举左右端点,如果相邻两个相等,就可以合并,所以伪代码为
1
2
3
4
5
6for i (n-1) ~ 1
for j (i+1) ~ n
for k i ~ j
if(f[i][k] == f[k+1][j])
f[i][j] = max(~, f[i][k]+1);
ans = max(~, f[i][j]);答案即为ans.
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const int Maxn = 300;
inline int sc() {
int xx = 0, ff = 1; char cch = gc;
while(!isdigit(cch)) {
if(cch == '-') ff = -1; cch = gc;
}
while(isdigit(cch)) {
xx = (xx << 1) + (xx << 3) + (cch ^ '0'); cch = gc;
}
return xx * ff;
}
inline void out(int x) {
if(x < 0) pc('-'), x = -x;
if(x >= 10)
out(x / 10);
pc(x % 10 + '0');
}
int n, ans;
int f[Maxn][Maxn];
int main() {
n = sc();
for(re int i = 1; i <= n; ++i)
f[i][i] = sc(), ans = std :: max(ans, f[i][i]);
for(re int i = n - 1; i >= 1; --i)
for(re int j = i + 1; j <= n; ++j)
for(re int k = i; k < j; k++) {
if(f[i][k] == f[k + 1][j]) {
f[i][j] = std :: max(f[i][j], f[i][k] + 1);
}
ans = std :: max(ans, f[i][j]);
}
out(ans), pc('\n');
return 0;
}
// Coded by dy.
rp++