解题思路
1.差分数组适用原理
2.具体代码实现
问题要求找出一个给定数列中,所有可能的特定子序列的数量。特定子序列的条件是,序列的任意一段都必须以0开始或以0结束,且序列中至少包含一个正数。这可以转化为寻找数列中满足某些条件的峰和谷的数量。一个“峰”是指一个元素,其值大于其左右相邻的元素值;一个“谷”是指一个元素,其值小于其左右相邻的元素值。
(1)输入处理与去重
- 输入处理:读取数列长度
n
和数列arr
。同时初始化变量maxA
为数列中的最大元素,用于后续构建差分数组。 - 去重:使用
unique
函数去除数列中连续重复的元素,因为连续重复的元素不影响找出的满足条件的子序列数量。去重后需要用erase
方法缩减数组大小,去除重复后剩余的部分。
(2)构建差分数组
差分数组是一种常用于处理区间更新的技巧。在本问题中,我们利用差分数组来标记数列中的“峰”和“谷”:
- 初始化差分数组:创建一个新的数组
diff
,其长度比arr
的最大元素大2。这是为了确保数组索引不会越界,并能容纳所有可能的值。 - 填充差分数组:
- 如果序列非空,在
diff[0]
加1,代表从数列的最小值开始计数。 - 遍历处理后的数列
arr
(已去重),根据每个元素相对于其邻居的大小关系,更新diff
。对于每个局部极大值(即“峰”),在其对应的diff
中减1;对于每个局部极小值(即“谷”),在其对应的diff
中加1。
- 如果序列非空,在
(3)计算最终结果
遍历差分数组 diff
,通过累加差分值来更新当前的子序列数 num
。同时,更新 maxNum
以记录遇到的最大子序列数。最后,maxNum
就是我们要找的满足条件的最大子序列数。
完整代码
【100分代码-差分数组】
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n, num, maxA, maxNum;
int main() {
cin >> n;
vector<int>arr(n + 2, 0);
for (size_t i = 1; i <= n; i++)
{
cin >> arr[i];
maxA = max(maxA, arr[i]);
}
auto last = unique(arr.begin(), arr.end());
arr.erase(last, arr.end());
vector<int>diff(maxA + 2, 0);
if (arr.size() != 0) diff[0]++;
for (size_t i = 1; i < arr.size() - 1; i++)
{
if (arr[i - 1] < arr[i] && arr[i] > arr[i + 1]) diff[arr[i]]--;
if (arr[i - 1] > arr[i] && arr[i] < arr[i + 1]) diff[arr[i]]++;
}
for (int i = 0; i < diff.size(); i++)
{
num += diff[i];
maxNum = max(maxNum, num);
}
cout << maxNum;
return 0;
}
【70分思路-暴力枚举】
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n, maxA, maxNum;
int main() {
cin >> n;
vector<int>arr(n);
for (size_t i = 0; i < n; i++)
{
cin >> arr[i];
maxA = max(maxA, arr[i]);
}
for (size_t i = 1; i <= maxA; i++)
{
vector<int>arrTemp = arr;
int num = 0;
for (auto& it : arrTemp) {
if (it < i) it = 0;
else it = 1;
}
auto last = unique(arrTemp.begin(), arrTemp.end());
arrTemp.erase(last, arrTemp.end());
for (auto& it : arrTemp) {
num += it;
}
maxNum = max(maxNum, num);
}
cout << maxNum;
return 0;
}