题目连接
1045 Favorite Color Stripe (30分)
题目大意
给定一个Eva喜欢的颜色序列和一个总的颜色序列,从总的颜色序列中找出按Eva喜欢的颜色序列顺序出现的最长子序列。有点绕,结合样例来说明什么意思。假设Eva喜欢的颜色序列为 {2 3 1 5 6}
,总的颜色序列为{2 2 4 1 5 5 6 3 1 1 5 6}
.那么需要从总的颜色序列中找出符合题意的序列有 {2 2 1 1 1 5 6}, {2 2 1 5 5 5 6}, {2 2 1 5 5 6 6}, {2 2 3 1 1 5 6}.
其中第一个序列按照2 1 5 6
的顺序出现,满足。
第二,三个序列按照 2 1 5 6
的顺序出现,满足。
第四个序列按照2 3 1 5 6
的顺序出现,满足。
思路
用动态规划实现即可,dp[c]表示以颜色c结尾的序列长度,设dp[j]表示以颜色j结尾的序列长度,那么状态转移方程可以表示为:
dp[c] = max(dp[j]+1,dp[c]);
为了保证dp[j]表示的是dp[c]更新之前的长度,这里设置了temp来表示dp[c]未更新前的最长序列长度,所以状态转移方程为:
dp[c] = max(temp[j]+1,dp[c]);
另外,Eva喜欢的颜色的出现顺序,可以用一个数组w来表示。由于总的颜色序列中不一定含有Eva所喜欢的颜色,所以在执行状态转移方程前,需要简单地判断一下。所以就很容易地写出了下面的代码。
总的来说,程序的时间复杂度为O(nm),其中m为颜色的总数(给的最大为200)。
AC代码
#include<iostream>
#define maxn 10010
#define maxc 205
using namespace std;
int n, m, l, ans = 0;
int w[maxc];
int dp[maxc],temp[maxc];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int c;
cin >> n >> m; //n没什么卵用
for (int i = 1; i <= m; i++) {
cin >> c;
w[c] = i;
}
cin >> l;
for (int i = 0; i < l; i++) {
cin >> c;
if (!w[c]) continue;
for (int j = 0; j < maxc; j++) {
if (!w[j] ||w[j] > w[c]) continue;
dp[c] = max(dp[c], temp[j] + 1);
}
dp[c] = max(1, dp[c]);
ans = max(dp[c], ans);
for (int j = 0; j < maxc; j++) { //temp记录了上次的dp
temp[j] = dp[j];
}
}
cout << ans;
return 0;
}