CSP-202109-2

202109-2

非零线段划分-题目描述

A1,A2,⋯,An 是一个由 n 个自然数(非负整数)组成的数组。我们称其中 Ai,⋯,Aj 是一个非零段,当且仅当以下条件同时满足:

1≤i≤j≤n;
对于任意的整数 k,若 i≤k≤j,则 Ak>0;
i=1 或 Ai−1=0;
j=n 或 Aj+1=0。

下面展示了几个简单的例子:

A=[3,1,2,0,0,2,0,4,5,0,2] 中的 4 个非零段依次为 [3,1,2]、[2]、[4,5] 和 [2];
A=[2,3,1,4,5] 仅有 1 个非零段;
A=[0,0,0] 则不含非零段(即非零段个数为 0)。

现在我们可以对数组 A 进行如下操作:任选一个正整数 p,然后将 A 中所有小于 p 的数都变为 0。试选取一个合适的 p,使得数组 A 中的非零段个数达到最大。若输入的 A 所含非零段数已达最大值,可取 p=1,即不对 A 做任何修改。

输入格式

从标准输入读入数据。

从标准输入读入数据。

输入的第一行包含一个正整数 n。

输入的第二行包含 n 个用空格分隔的自然数 A1,A2,⋯,An。

输出格式

输出到标准输出。

仅输出一个整数,表示对数组 A 进行操作后,其非零段个数能达到的最大值。

输入
11
3 1 2 0 0 2 0 4 5 0 2
输出
5
说明/提示
样例解释

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

子任务

70%的测试数据满足n < 1000

全部的测试数据满足n < 5 * 10^5 ,且数组中的每一个数均不超过10 ^ 4。


思路解析

把它看作若干个岛屿,水面从最高点逐步下降。

暴力模拟的话,5 * 10 ^ 5的陆地长度,10^4的水面高度

每个高度的水面都从头遍历一遍所有的陆地,然后再寻找遍历结果的最大值

那乘起来就是10^9,肯定超时。

所以,最好能只过一遍,只计算当水面下降时,哪个位置的岛屿会露出来/沉下去。

我们用1 4 2 3 9 0 9 0 0 8 1 3 0举例

你看那个4,当水面从4降低到3的时候,他就会露出来。

所以,我们用类似于差分的思想

假设待处理数组为ls,把ls[i]分为三种:

1.咋都不会改变岛屿数量。中间值就可以,比如1,2,3中间的2,咋都不会变

2.可能增加岛屿数量。比如1,3,1,中间的3,水面小于1的时候3不影响,1-3的时候3是一个岛屿,大于等于3的时候不影响

3.可能减少岛屿数量。比如3,1,3,中间的1,同上。

所以,我们不难看出,ls[i]只会改变当水涨到 ls[i] 的值,且情况1不会改变,情况2,3分别会+1/-1。

因此,我们新建一个列表,暂且就叫它ls2,专门用来存储当水涨到ls[i]时,岛屿总数改变的数量。

不难看出,ls2枚举值的最大值等于ls[i]的最大值。

所以,对于待处理数组,先从头到尾过一遍,按照ls[i]的三种可能,创造出来ls2数组

然后遍历ls2,找到sum[i]最大的值,输出就可以了。

输入输出部分
# 老规矩,先考虑输入输出
n = int(input())
ls = list(map(int, input().split()))
# 输入处理完毕

#
# 核心代码
#


print(maxn, end = "")
核心代码
#创建ls2数组
ls2 = [0 for i in range(max(ls) + 1)]

# 这里有个小问题
# 假设只有3 1 1 3,假设水在1这里,那应该是两个峰
# 3:1 1:0 1:0 3:1
# 但是,如果水在1的位置,淹没了,却不会减去
# 所以,应该把它变成 3:1 1:-1 3:1
# 因此需要去重。
# 遍历ls1,给ls2填数
ls_tmp = ls[:]
ls = []
ls.append(ls_tmp[0])
for i in range(len(ls_tmp)-1):
    if ls_tmp[i] != ls_tmp[i+1]:
        ls.append(ls_tmp[i+1])
#去重结束



#然后针对去重后的数组开始处理
for i in range(1,len(ls) - 1):
    if ls[i] > ls[i-1] and ls[i] > ls[i+1]:
        ls2[ ls[i] ] += 1
    elif ls[i] < ls[i-1] and ls[i] < ls[i+1]:
        ls2[ ls[i] ] -= 1
ls2[0] = 0


#给ls2的头和尾填数  
if ls[0] > ls[1]:
    ls2[ls[0]] += 1

n = len(ls)
if ls[n-1] > ls[n - 2]:
    ls2[ls[n-1]] += 1
#这里需要注意的是,头尾只可能成为峰,不会成为谷。
#比如1 3 1,最少也是1。

maxn = 0
maxn_tmp = 0
for i in ls2[::-1]:
    maxn_tmp += i
    maxn = max(maxn, maxn_tmp)
汇总代码
n = int(input())
ls = list(map(int, input().split()))
ls2 = [0 for i in range(max(ls) + 1)]
ls_tmp = ls[:]
ls = []
ls.append(ls_tmp[0])
for i in range(len(ls_tmp)-1):
    if ls_tmp[i] != ls_tmp[i+1]:
        ls.append(ls_tmp[i+1])
for i in range(1,len(ls) - 1):
    if ls[i] > ls[i-1] and ls[i] > ls[i+1]:
        ls2[ ls[i] ] += 1
    elif ls[i] < ls[i-1] and ls[i] < ls[i+1]:
        ls2[ ls[i] ] -= 1
ls2[0] = 0
if ls[0] > ls[1]:
    ls2[ls[0]] += 1
n = len(ls)
if ls[n-1] > ls[n - 2]:
    ls2[ls[n-1]] += 1
maxn = 0
maxn_tmp = 0
for i in ls2[::-1]:
    maxn_tmp += i
    maxn = max(maxn, maxn_tmp)
print(maxn, end = "")
评测链接

【CSP 202109-2】首页 - 计算机软件能力认证考试系统

最近的文章

CSP-202206-2

出行计划-题目描述暑假要到了。可惜由于种种原因,小 P 原本的出游计划取消。失望的小 P 只能留在西西艾弗岛上度过一个略显单调的假期……直到……某天,小 P 获得了一张神秘的藏宝图。西西艾弗岛上种有 n 棵树,这些树的具体位置记录在一张绿化图上。简单地说,西西艾弗岛绿化图可以视作一个大小为 (L+1…

继续阅读
更早的文章

游戏说明-骨骼

当风吹过海岸,娇艳的花儿在河流旁盛开银火虫在草坪上四散飞舞,近在咫尺的彩虹从河流延伸到天边…这样梦一般的场景,你是否会想要跳舞一曲? …

继续阅读