Processing math: 100%

Catalog
题解 CF607B 【Zuma】

查看原题请戳这里

题目大意:

从一个序列中每次取出一个回文串,剩余部分拼起来形成一个新的序列,问取几次能把这个序列取完。


这道题我们可以用区间DP的方法去解决。

a[1,n]为题目给出的序列,用f[i][j]表示将区间[i,j]中的数取完需要的最少的次数,那么显然f[i][i]=1,且当a[i]=a[j]f[i][i+1]=1,当a[i]a[i+1]f[i][i+1]=2。有用我们再后续进行动态规划时更新的最短的区间长度为3,所以f[i][i]f[i][i+1]两种情况需要特殊处理。

在更新f[i][j]时,最简单的思路就是把f[i][j]分成f[i][k]f[k+1][j]两部分进行处理(其中k[i,j)),即

f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]),k[i,j)

而对于a[i]=a[j]的情况,当区间[i+1,j1]还剩最后一个可以一次取出的序列b时(显然b是回文的),我们可以将a[i]a[j]b组成一个新的回文串同时取出(即组成a[i] b a[j]),从而我们可知当a[i]=a[j]时,

f[i][j]=min(f[i][j],f[i+1][j1])

然后根据上述两式DP即可。

code:

cpp
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
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
#define INF 1000000009
#define qwq printf("qwq\n");

using namespace std;

int read() {
register int x = 0,f = 1;register char ch;
ch = getchar();
while(ch > '9' || ch < '0'){if(ch == '-') f = -f;ch = getchar();}
while(ch <= '9' && ch >= '0'){x = x * 10 + ch - 48;ch = getchar();}
return x * f;
}

int n,a[505],f[505][505];

int main() {
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
f[i][j] = INF;
for(int i = 1; i <= n; i++) f[i][i] = 1, f[i][i + 1] = 1;
for(int i = 1; i < n; i++) if(a[i] != a[i + 1]) f[i][i + 1]++;
for(int i = 3; i <= n; i++)
for(int j = 1; j <= n - i + 1; j++) {
int l = j, r = j + i - 1;
if(a[l] == a[r]) f[l][r] = f[l + 1][r - 1];
for(int k = l; k < r; k++) f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r]);
}
printf("%d\n", f[1][n]);
return 0;
}
Author: wflight
Link: http://yoursite.com/2020/07/31/题解-CF607B-【Zuma】/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
  • 支付寶

Comment