【CSP试题回顾】202109-2-非零段划分(优化)

CSP-202109-2-非零段划分

解题思路

1.差分数组适用原理

2.具体代码实现

问题要求找出一个给定数列中,所有可能的特定子序列的数量。特定子序列的条件是,序列的任意一段都必须以0开始或以0结束,且序列中至少包含一个正数。这可以转化为寻找数列中满足某些条件的峰和谷的数量。一个“峰”是指一个元素,其值大于其左右相邻的元素值;一个“谷”是指一个元素,其值小于其左右相邻的元素值。

(1)输入处理与去重

  1. 输入处理:读取数列长度 n 和数列 arr。同时初始化变量 maxA 为数列中的最大元素,用于后续构建差分数组。
  2. 去重:使用 unique 函数去除数列中连续重复的元素,因为连续重复的元素不影响找出的满足条件的子序列数量。去重后需要用 erase 方法缩减数组大小,去除重复后剩余的部分。

(2)构建差分数组

差分数组是一种常用于处理区间更新的技巧。在本问题中,我们利用差分数组来标记数列中的“峰”和“谷”:

  1. 初始化差分数组:创建一个新的数组 diff,其长度比 arr 的最大元素大2。这是为了确保数组索引不会越界,并能容纳所有可能的值。
  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;
}
  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值