PTA 1045(DP,最长不下降子序列)
PTA 1045(DP,最长不下降子序列)
Eva is trying to make her own color stripe out of a given one. She would like to keep only her favorite colors in her favorite order by cutting off those unwanted pieces and sewing the remaining parts together to form her favorite color stripe.
It is said that a normal human eye can distinguish about less than 200 different colors, so Eva’s favorite colors are limited. However the original stripe could be very long, and Eva would like to have the remaining favorite stripe with the maximum length. So she needs your help to find her the best result.
Note that the solution might not be unique, but you only have to tell her the maximum length. For example, given a stripe of colors {2 2 4 1 5 5 6 3 1 1 5 6}. If Eva’s favorite colors are given in her favorite order as {2 3 1 5 6}, then she has 4 possible best solutions {2 2 1 1 1 5 6}, {2 2 1 5 5 5 6}, {2 2 1 5 5 6 6}, and {2 2 3 1 1 5 6}.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=200) which is the total number of colors involved (and hence the colors are numbered from 1 to N). Then the next line starts with a positive integer M (<=200) followed by M Eva’s favorite color numbers given in her favorite order. Finally the third line starts with a positive integer L (<=10000) which is the length of the given stripe, followed by L colors on the stripe. All the numbers in a line are separated by a space.
Output Specification:
For each test case, simply print in a line the maximum length of Eva’s favorite stripe.
Sample Input:
6
5 2 3 1 5 6
12 2 2 4 1 5 5 6 3 1 1 5 6
Sample Output:
7
题目大意:n为颜色范围的最大值,给你长度为m 的Eva喜欢的颜色序列(不重复,有顺序),再给你一个长度为l的颜色序列,按照Eva喜欢的颜色裁剪与缝合,请你给出最长的Eva喜欢的颜色序列的长度(顺序一致即可,颜色不需要全部出现)
现在要去掉这个序列中的不喜欢的颜色,然后求剩下序列的一个子序列,使得这个子序列表示的颜色顺序符合自己喜欢的颜色的顺序,不一定要所有喜欢的颜色都出现。 ---柳婼
分析:要解决 “Favorite Color Stripe” 问题,我们可以通过动态规划将其转化为最长非递减子序列(LNDS) 问题来求解。
算法步骤:
- 问题转化
题目要求从原条纹中保留 Eva 喜欢的颜色,且保留的颜色必须按照她喜欢的顺序排列,目标是找到最长的符合条件的条纹长度。
-
核心观察:Eva 喜欢的颜色有固定顺序(如
[2,3,1,5,6]),保留的颜色必须遵循这个顺序的 “相对关系”(例如 2 可以在 3/1/5/6 之前,3 可以在 1/5/6 之前,以此类推)。 -
转化思路:
- 给喜欢的颜色赋予 “顺序索引”(如 2→0,3→1,1→2,5→3,6→4)。
- 过滤原条纹,仅保留喜欢的颜色,并将这些颜色替换为对应的顺序索引,得到一个新序列
nums。 - 问题转化为求
nums的最长非递减子序列(LNDS) 的长度(非递减即符合喜欢的顺序)
-
预处理(映射与过滤)
- 建立映射关系:
用一个数组pos存储喜欢的颜色对应的顺序索引(例如pos[2]=0,pos[3]=1),非喜欢的颜色标记为-1。 - 过滤原条纹:
遍历原条纹,仅保留pos[color]≠-1的颜色(即喜欢的颜色),并将其替换为对应的索引,生成序列nums。
- 建立映射关系:
-
动态规划求解 LNDS
定义状态
设dp[i]表示以nums[i]为结尾的最长非递减子序列的长度。
状态初始化
每个元素自身可构成一个长度为 1 的子序列,因此dp[i] = 1(对所有i)。
状态转移方程
对于每个i(从 0 到len(nums)-1),遍历所有j < i:
- 若
nums[j] ≤ nums[i](即nums[j]的顺序在nums[i]之前或相同),则dp[i] = max(dp[i], dp[j] + 1)(用j结尾的子序列长度加 1 更新i的长度)。
- 结果
dp数组中的最大值即为最长符合条件的条纹长度。
代码实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int N, M, L;
cin >> N;
cin >> M;
vector<int> fav(M);
vector<int> pos(N + 1, -1); // 颜色到索引的映射,非喜欢的颜色为-1
for (int i = 0; i < M; ++i) {
cin >> fav[i];
pos[fav[i]] = i;
}
// 读取原条纹并过滤、转换为索引序列
cin >> L;
vector<int> nums;
for (int i = 0; i < L; ++i) {
int color;
cin >> color;
if (pos[color] != -1) { // 只保留喜欢的颜色
nums.push_back(pos[color]);
}
}
// 计算最长非递减子序列(LNDS)
int k = nums.size();
if (k == 0) { // 没有喜欢的颜色
cout << 0 << endl;
return 0;
}
vector<int> dp(k, 1); // dp[i]表示以nums[i]结尾的LNDS长度
int max_len = 1;
for (int i = 1; i < k; ++i) {
for (int j = 0; j < i; ++j) {
if (nums[j] <= nums[i]) { // 符合非递减条件
dp[i] = max(dp[i], dp[j] + 1);
}
}
max_len = max(max_len, dp[i]);
}
cout << max_len << endl;
return 0;
}

浙公网安备 33010602011771号