2 条题解
-
13
本题中的峡谷序列,原理和山峰序列类似,但需要注意区分,否则容易陷入误区。 可能会有同学尝试在山峰序列代码的基础上交换f数组和g数组而陷入误区,这是因为对f数组和g数组的状态定义理解的不够清楚,我们在山峰子序列问题中用f[i]表示从左往右以i结尾时的最长上升子序列长度,g[i]表示从右往左以i结尾时的最长上升子序列长度,若想要表示以i结尾时的最长下降子序列长度,则需要调整中间的查询过程。
本题的数据规模较小,可以使用O(n²)时间复杂度算法。
参考代码
for (int i = 1; i <= n; i++) { f[i] = 1; for (int j = 1; j < i; j++) { if (a[j] > a[i]) f[i] = max(f[i], f[j] + 1); } } for (int i = n; i >= 1; i--) { g[i] = 1; for (int j = n; j > i; j --) { if (a[j] > a[i]) g[i] = max(g[i], g[j] + 1); } }
如果使用二分优化,则需要将d数组初始为0,并且在二分查找时查询d数组中第一个小于等于a[i]的数的下标。
参考代码
int max_len(int x) { int l = 1, r = n, ans = n + 1; while (l <= r) { int mid = (l + r) / 2; if (d[mid] <= x) { ans = mid; r = mid - 1; } else { l = mid + 1; } } return ans; }
for (int i = 1; i <= n; i++) { int now = max_len(a[i]); f[i] = now; d[now] = a[i]; } memset(d, 0, sizeof(d)); for (int i = n; i >= 1; i--) { int now = max_len(a[i]); g[i] = now; d[now] = a[i]; }
-
9
这道题目要求找出给定序列中的最长峡谷子序列的长度。峡谷子序列是指先下降再上升的子序列。我们可以使用动态规划来解决这个问题。
首先,我们定义两个数组f和g,分别用来表示从左往右和从右往左的最长峡谷子序列长度。
对于f数组,我们从左往右遍历序列a,对于每个元素a[i],我们在其之前的所有元素中查找比它大的元素,并更新f[i]为其之前的最大峡谷子序列长度加1。即 f[i] = max(f[j] + 1, f[i]),其中j取值范围为[1, i-1],且a[j] > a[i]。
对于g数组,我们从右往左遍历序列a,对于每个元素a[i],我们在其之后的所有元素中查找比它大的元素,并更新g[i]为其之后的最大峡谷子序列长度加1。即 g[i] = max(g[j] + 1, g[i]),其中j取值范围为[i+1, n],且a[j] > a[i]。
最后,我们遍历f和g数组,计算f[i] + g[i] - 1的最大值,即为最长峡谷子序列的长度。
在实现过程中,我们可以使用二分查找来优化查找比当前元素大的最远位置的过程。具体做法是,维护一个辅助数组d,其中d[i]表示长度为i的最长上升子序列的末尾元素的最小值。在二分查找时,我们查询d数组中第一个小于等于当前元素a[i]的位置,即为满足条件的最远位置。
以上就是解决这个问题的思路和步骤。通过动态规划和二分查找,我们可以高效地求解最长峡谷子序列的长度。
#include <iostream> #include <vector> #include <cstring> using namespace std; int max_len(int x, vector<int>& d) { int l = 1, r = d.size() - 1, ans = d.size(); while (l <= r) { int mid = (l + r) / 2; if (d[mid] <= x) { ans = mid; r = mid - 1; } else { l = mid + 1; } } return ans; } int longestValleySubsequence(int n, vector<int>& a) { vector<int> f(n + 1, 1); vector<int> g(n + 1, 1); vector<int> d(n + 1, 0); for (int i = 1; i <= n; i++) { int now = max_len(a[i], d); f[i] = now; d[now] = a[i]; } memset(d.data(), 0, sizeof(int) * (n + 1)); for (int i = n; i >= 1; i--) { int now = max_len(a[i], d); g[i] = now; d[now] = a[i]; } int maxLength = 0; for (int i = 1; i <= n; i++) { maxLength = max(maxLength, f[i] + g[i] - 1); } return maxLength; } int main() { int n; cin >> n; vector<int> a(n + 1); for (int i = 1; i <= n; i++) { cin >> a[i]; } int result = longestValleySubsequence(n, a); cout << result << endl; return 0; }
- 1
信息
- ID
- 269
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- (无)
- 递交数
- 788
- 已通过
- 343
- 上传者