题解系列017 + 比赛系列006 | 优快云 第二十一届编程竞赛题解 + 建议

一、总体情况

得分:25+0+25+25=75(排名第5)

在这里插入图片描述

二、题目分析

第一题:合并序列

题目

鬼画符门莲台争夺战!虽然鬼画符门是一个三流门派但是近期为了改善宗门弟子质量。 特意引进了进化莲台。部分精英弟子会自己独占一块区域,或者几个精英弟子一块占领一块区域,他们占领的区域普通弟子不可以再占领,小艺作为普通 弟子想知道自己还能占领哪些地方。莲台区域以1开始,由小到大编号表示。

分析

较为容易,用 for 循环一次检验每个序列即可。(这里的 python 实现用到了数组切片

代码
class Solution:
    def __init__(self) -> None:
        pass
    
    def solution(self, N, arr, T):
        result = []
        l = len(T)
        for i in range(len(arr)):
            if len(arr[i])>=l and arr[i][:l]==T:
                result.append(arr[i])

        return result


if __name__ == "__main__":

    N = int(input().strip())
    
    arr = []
    for i in range(N):
        arr.append(input().strip())
    
    T = input().strip()

    sol = Solution()
    result = sol.solution(N, arr, T)
    result.sort()
    print("\n".join(result))

第二题:千问万问

题目

在这里插入图片描述

分析

根据 优快云 往届竞赛经验,数据范围一般不会很大,所以暴力枚举不失为本题的一个方案。当然,如果追求效率,可以采用二分搜索的方法。但由于时间考量,笔者选择枚举。(本题数据有锅,因此未得分)

代码
class Solution:
    def __init__(self) -> None:
        pass
    
    def solution(self, n, q, nums, arr):
        result = []

        for i in range(q):
            cnt = 0
            for j in nums:
                if j>=arr[i][0] and j<=arr[i][1]:
                    cnt = cnt+1
            result.append(cnt)

        return result


if __name__ == "__main__":
    
    arr_temp = [int(item) for item in input().strip().split()]
    
    n = int(arr_temp[0])
    q = int(arr_temp[1])
    
    nums = [int(item) for item in input().strip().split()]
    
    
    arr = []
    for i in range(q):
        arr.append([int(item) for item in input().strip().split()])
    

    sol = Solution()
    result = sol.solution(n, q, nums, arr)
    for i in range(len(result)):
        print(result[i])

第三题:连续子数组的最大和

题目

在这里插入图片描述

分析

动态规划几乎是每一届 优快云 竞赛的必考点,这次也不例外(虽然此题十分基础)。我们用 d p [ i ] \mathrm{dp}[i] dp[i] 表示以 i i i 号索引结尾的有着最大和的连续子数组。则:

  • 显然有 d p [ 0 ] = n u m s [ 0 ] \mathrm{dp}[0]=\mathrm{nums}[0] dp[0]=nums[0].
  • 从前往后维护 { d p [ i ] } \mathrm{\{dp[i]\}} {dp[i]} 数组:假如 d p [ i − 1 ] \mathrm{dp}[i-1] dp[i1] 已确定,则对于 d p [ i ] \mathrm{dp}[i] dp[i], 它要么包含 n u m s [ i − 1 ] \mathrm{nums}[i-1] nums[i1], 要么只有 n u m s [ i ] \mathrm{nums}[i] nums[i] 一项, 二者取最大并不要忘记追踪最大值即可.

根据以上思路,

代码
class Solution:
    def __init__(self) -> None:
        pass
    
    def solution(self, n, arr):
        dp = [0 for _ in range(n)]
        dp[0] = maxi = arr[0]
        for i in range(1, n):
            dp[i] = max(dp[i-1], 0)+arr[i]
            maxi = max(maxi, dp[i])

        return maxi

if __name__ == "__main__":


    n = int(input().strip())
    
    
    arr = [int(item) for item in input().strip().split()]
    
    
    sol = Solution()
    result = sol.solution(n, arr)

    print(result)

第四题:降水量

题目

在这里插入图片描述

分析

这题如果从整体考虑其实很复杂, 但假如单看每一个 x x x 坐标单元格的情况, 那么其实一目了然: 第 i i i 号位置的 “水面” 位置是以下两个数值中的较高者:

  • 包含 i i i 号位置的向左数最高的单元格和包含 i i i 号位置的向右数最高的单元格的较矮者.
  • 地平线, 即 0 0 0. (这只是因为题目要求)

值得注意的是, 这里只要稍微多写一些代码就能做到优化: 运用动态规划的方式维护上述所谓 “包含 i i i 号位置的向左 (右) 数最高的单元格” 的数值. 因此代码如下:

代码
class Solution:
    def __init__(self) -> None:
        pass
    
    def solution(self, n, arr):
        result = 0

        incleftmax = [arr[0]]+[0 for i in range(n-1)]
        incrightmax = [0 for i in range(n-1)]+[arr[n-1]]
        for i in range(1, n):
            incleftmax[i] = max(incleftmax[i-1], arr[i])
        for i in range(n-2, -1, -1):
            incrightmax[i] = max(incrightmax[i+1], arr[i])
        for i in range(n):
            result = result+max(min(incleftmax[i], incrightmax[i]), 0)-arr[i]

        return result

if __name__ == "__main__":


    n = int(input().strip())
    
    
    arr = [int(item) for item in input().strip().split()]
    
    
    sol = Solution()
    result = sol.solution(n, arr)

    print(result)

三、写在最后:对 优快云 竞赛的一些建议

  1. 仍然希望 优快云 在赛后能第一时间发布官方题解, 以供参考学习.
  2. 希望 优快云 在之后的比赛中尽可能不出现数据出锅的问题, 即使有问题, 赛后也能对有争议的数据进行及时查验反馈, 并以此为据重新判分, 以鼓励选手集思广益.
  3. 题目描述过分简略和不清晰仍是一大问题, 对题面描述, 数据范围, 样例分析等没有看到形式上的改进.

欢迎关注我的博客!
我的 GitHub 账号: 欢迎 Fork + PR!
我的洛谷账号:这是我
我的洛谷团队:这是我的团队
欢迎大家关注我,在项目上与我协作哦!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值