双指针,CF 1167E - Range Deleting

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

1167E - Range Deleting


二、解题报告

1、思路分析

力扣有个差不多的但是简单点的题目:2972. 统计移除递增子数组的数目 II

由于f(l, r)是值域pair,所以我们考虑将原数组a转换为值域数组nums

nums[i] = (v, l, r),代表值v,最早出现下标为l,最晚出现下标为r

任意一个原数组删除部分值域后剩下的的递增数组都可以对应到nums中的一个“递增数组”:

(“递增数组”代表力扣那道题的移除子数组后剩下的元素形成递增数组的子数组)

nums(i, j),任意 nums[k], i <= k < j, 有nums[k].r < nums[k + 1].l

也就是说,原操作得到的递增数组 和 nums 中的“递增数组”是一个1-1映射关系

那么我们求nums上的“递增数组”的个数即可

这就是比较典的问题了

考虑只保留前缀,那么我们预处理出递增前缀为nums[0, i]

那么贡献就是

nums[i + 1][0] * (x - nums[n - 1][0] + 1),即至少要删除掉[nums[i].v + 1, x]的数

然后考虑一般情况:

双指针i, j

i初始就是最长递增前缀的下标,j初始就是n - 1(n是nums的长度)

由于二者具有单调性: j 靠左移动,和其匹配的i的边界也得左移

所以我们维护i, j,对于一个j,其贡献就是 (nums[j].v - nums[j - 1].v) * nums[i].v,即至少要删除区间下界不超过nums[i].v + 1, 上界不小于nums[j - 1].v

2、复杂度

时间复杂度: O(N)空间复杂度:O(N)

3、代码详解

 ​
import sys

input = lambda: sys.stdin.readline().strip()
MII = lambda: map(int, input().split())
LMI = lambda: list(map(int, input().split()))
LI = lambda: list(input())
II = lambda: int(input())
fmax = lambda x, y: x if x > y else y
fmin = lambda x, y: x if x < y else y
P = 10**9 + 7

def solve():
    n, x = MII()
    pos = [[-1, -1] for _ in range(x + 1)]
    a = LMI()
    for i, v in enumerate(a):
        if pos[v][0] == -1:
            pos[v][0] = i
        pos[v][1] = i

    nums = []
    for v, (a, b) in enumerate(pos):
        if ~a:
            nums.append([v, a, b])

    n = len(nums)
    i = 0
    while i + 1 < n and nums[i][2] < nums[i + 1][1]:
        i += 1

    if i == n - 1:
        print((x + 1) * x // 2)
        return

    res = nums[i + 1][0] * (x - nums[n - 1][0] + 1)

    j = n - 1
    while j == n - 1 or nums[j][2] < nums[j + 1][1]:
        while ~i and nums[i][2] >= nums[j][1]:
            i -= 1

        res += nums[i + 1][0] * (nums[j][0] - nums[j - 1][0])
        j -= 1

    print(res)

if __name__ == "__main__":
    T = 1
    # T = II()
    for _ in range(T):
        solve()

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值