IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> csp真题 202109-2非零段划分C++代码(100分) -> 正文阅读

[C++知识库]csp真题 202109-2非零段划分C++代码(100分)

试题编号: 202109-2
试题名称: 非零段划分
时间限制: 1.0s
内存限制: 512.0MB
在这里插入图片描述
在这里插入图片描述

样例1输入

11
3 1 2 0 0 2 0 4 5 0 2

样例1输出

5

样例1解释
p=2时,A=[3,0,2,0,0,2,0,4,5,0,2],5个非零段依次为[3]、[2]、[2]、[4、5]和[2];此时非零段个数达到最大。

样例2输入

14
5 1 20 10 10 10 10 15 10 20 1 5 10 15

样例2输出

4

样例2解释
p=12时,A=[0,0,20,0,0,0,0,15,0,20,0,0,0,15],4个非零段依次为[20]、[15]、[20]和[15];此时非零段个数达到最大。

样例3输入

3
1 0 0

样例3输出

1

样例3解释
p=1时,A=[1,0,0],此时仅有1个非零段[1],非零段个数达到最大。

样例4输入

3
0 0 0

样例4输出

0

样例4解释
无论p取何值,A都不含有非零段,故非零段个数至多为0。
在这里插入图片描述
70分代码及思路:
思路:
1.将所有数据存储到一个数组A中,并记录最大值max_A;
2.p从1开始遍历到最大值max_A,记录每一次p值下的非零段的个数最大值到数组max1中。
3.判断非零段个数:遍历数组,找到每一个不为0的值,如果该数前一个数为0或者该数是数组的第一个数,非零段个数加1。
4.遍历数组max1,输出最大值。
分析:
该方法属于常规思路,比较简单,无任何算法优化,有很多循环遍历,且有双层循环,由题目给出的数据范围,在双层循环中,循环次数有可能达到10^9,显然会超时。

#include <iostream> 
using namespace std;

int main() 
{
	int n;
	int i=0,p=0,max_A=0,max=0;
	
	cin>>n;
	int A[n]={0};
	for(i=0;i<n;i++)
	{
		cin>>A[i];
		if(A[i]>max_A)	//记录数组A中的最大值 
		{
			max_A=A[i];
		}
	}
	int max1[max_A]={0};	//开辟数组用来存储每一个p值下的非零段的最大值 
	for(p=1;p<max_A;p++)	//p从1开始遍历 
	{
		for(i=0;i<n;i++)	//将数组中小于p的数置为0 
		{
			if(A[i]<p)
			{
				A[i]=0;
			}
		}
		for(i=0;i<n;i++)	//遍历数组 
		{
			if(A[i]!=0){
			//若不为0,判断是否是数组的第一个数或者该数的前一个数为0,如果是,非零段加1 
				if(i==0||A[i-1]==0){
					max=max+1;
				}
			}
		}
		max1[p]=max;
		max=0;
	}
	for(i=1;i<max_A;i++)	
		if(max1[i]>max){
			max=max1[i];
		}
	cout<<max;
	return 0;
}

提交结果如下:
在这里插入图片描述
如果要拿到满分,那么用常规的思路逻辑肯定不行,必须要做一定的优化处理,在参考b站视频教程后整理如下:
1.读入数组时插入set,对数组进行去重和排序,(方便p值的选取)。
2.利用向量vector,将set集合中每个元素出现的位置存储在同一个vector向量中。
3.统计初始的非零段个数作为参考值。
(与前一种方法有点区别,在数组开头和最后加0,只需判断当前数不为0并且前一位数为0,非零段个数加1即可)
4.p依次从set中取值(从小到大)(如果值为0,跳过),依据位置向量获得每个值在数组A中的位置。
将对应位置的值赋值为0
如果该位置的前后的值都大于0,则非零段数加1;
如果该位置的前后的值都等于0,则非零段数减1;
其他情况下非零段个数不变。

更新非零段的最大值。
该方法的优点在于:
通过向量对应的位置坐标,判断坐标位置前后元素的值进行判断即可,不必在每一个p值下都对数组进行循环遍历,降低了时间复杂度。
此方法思路来源b站,可参考b站视频内容

满分代码:

#include <bits/stdc++.h>
using namespace std;

int A[500002]= {0};
vector<int> Vector[10001];
set<int> Set;

int main() {
	int n;
	cin>>n;
	for(int i=1; i<=n; i++) {
		cin>>A[i];
		Set.insert(A[i]);
		Vector[A[i]].push_back(i);
	}

	int number=0;	//非零段个数
	for(int i=1; i<=n; i++) {	//找出当前非零段的个数
		if((A[i]>0)&&(A[i-1]==0))
			number++;
	}

	int temp;
	int number_max;	//非零段个数的最大值
	temp=number_max=number;

	set<int>::iterator p=Set.begin();//用迭代器来访问set集合
	//p的值从集合开始遍历
	if(*p==0)		//如果集合中的元素为0,则直接从下一个元素开始
		p++;
	for(p; p!=Set.end(); p++) {
		vector<int> &Vector1=Vector[*p];	//引用Vector[*p]为Vector1 
		for(int i=0; i<Vector1.size(); i++) {	//集合中该元素出现的总次数
			int k=Vector1[i];	
			A[k]=0;
			if((A[k-1]!=0)&&(A[k+1]!=0))
				temp++;
			if((A[k-1]==0)&&(A[k+1]==0))
				temp--;
		}
		number_max=max(number_max,temp);
	}
	cout<<number_max<<endl;
	return 0;

}

提交结果如下:
在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-03 12:51:42  更:2021-12-03 12:53:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:14:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码