线段树:最优清零方案

news/2024/7/7 21:12:18

最优清零方案

问题描述

给定一个长度为 N N N 的数列 A 1 , A 2 , ⋯   , A N A_{1}, A_{2}, \cdots, A_{N} A1,A2,,AN 。现在小蓝想通过若干次操作将这个数列中每个数字清零。

每次操作小蓝可以选择以下两种之一:

  1. 选择一个大于 0 的整数, 将它减去 1 ;
  2. 选择连续 K K K 个大于 0 的整数, 将它们各减去 1 。

小蓝最少经过几次操作可以将整个数列清零?

输入格式

输入第一行包含两个整数 N N N K K K

第二行包含 N N N 个整数 A 1 , A 2 , ⋯   , A N A_{1}, A_{2}, \cdots, A_{N} A1,A2,,AN

输出格式

输出一个整数表示答案。

样例输入

4 2
1 2 3 4

样例输出

6

评测用例规模与约定

对于 20 20 \\% 20 的评测用例, 1 ≤ K ≤ N ≤ 10 1 \leq K \leq N \leq 10 1KN10

对于 40 40 \\% 40 的评测用例, 1 ≤ K ≤ N ≤ 100 1 \leq K \leq N \leq 100 1KN100

对于 50 50 \\% 50 的评测用例, 1 ≤ K ≤ N ≤ 1000 1 \leq K \leq N \leq 1000 1KN1000

对于 60 60 \\% 60 的评测用例, 1 ≤ K ≤ N ≤ 10000 1 \leq K \leq N \leq 10000 1KN10000

对于 70 70 \\% 70 的评测用例, 1 ≤ K ≤ N ≤ 100000 1 \leq K \leq N \leq 100000 1KN100000

对于所有评测用例, 1 ≤ K ≤ N ≤ 1000000 , 0 ≤ A i ≤ 1000000 1 \leq K \leq N \leq 1000000,0 \leq A_{i} \leq 1000000 1KN1000000,0Ai1000000

解题思路

分析
1、每次只能对某个数字减去 1 1 1,或者对长度为 K K K的序列减去1
——单点修改、区间修改

2、从最左端出发,即区间 [ 1 , K ] [1,K] [1,K],如果对该区间进行减法,则最多只能减去该区间的最小值。如果区间最小值为0,则无法进行减法,那也就是第一个数字只能一次一次消去。
——如何选择单点修改和区间修改

根据上述分析,我们只需要从左往右枚举左端点 l l l,此时可以处理的区间为 [ l , l + k − 1 ] [l,l+k-1] [l,l+k1],需要求出区间最小值 m i mi mi

  • 如果 m i = = 0 mi==0 mi==0,答案加上此时的 a [ l ] a[l] a[l],说明无法以该起点进行区间消除,只能单个消除。
  • 如果 m i ≠ 0 mi\neq0 mi=0,答案加上 m i mi mi,然后对区间 [ l , l + k − 1 ] [l,l+k-1] [l,l+k1]进行区间减法,统一减去 m i mi mi。然后再加上此时的 a [ l ] a[l] a[l],因为此时剩下的 a [ l ] a[l] a[l]部分也只能单个消除。

AC_Code(Python)

# -*- coding: utf-8 -*-
# @Author : BYW-yuwei
# @Software: python3.8.6
maxn = 1000000 + 10
tree_mi = [0] * (maxn * 4)
tree_add = [0] * (maxn * 4)

n, k = list(map(int, input().split()))
a = list(map(int, input().split()))
a = [0, *a]

#线段树模板
#利用左右儿子信息更新节点o
def push_up(o):
    tree_mi[o] = min(tree_mi[o << 1], tree_mi[o << 1 | 1])

#利用节点o的lazy标记add更新左右儿子
def push_down(o):
    if tree_add[o] != 0:
        tree_add[o << 1] += tree_add[o]
        tree_mi[o << 1] += tree_add[o]
        tree_add[o << 1 | 1] += tree_add[o]
        tree_mi[o << 1 | 1] += tree_add[o]
        tree_add[o] = 0

#建树
def build(o, l, r):
    tree_add[o] = 0
    if l == r:
        tree_mi[o] = a[l]
        return
    mid = (l + r) >> 1
    build(o << 1, l, mid)
    build(o << 1 | 1, mid + 1, r)
    push_up(o)

#查询区间[L,R]的最小值
def query(o, l, r, L, R):
    if L <= l and r <= R:
        return tree_mi[o]
    push_down(o);
    mid = (l + r) >> 1
    ans = 1000000000;
    if L <= mid:
        ans = min(ans, query(o << 1, l, mid, L, R))
    if R > mid:
        ans = min(ans, query(o << 1 | 1, mid + 1, r, L, R))
    return ans

#区间更新[L,R]统一加上val
def update(o, l, r, L, R, val):
    if L <= l and r <= R:
        tree_mi[o] += val
        tree_add[o] += val
        return
    push_down(o);
    mid = (l + r) >> 1
    if L <= mid:
        update(o << 1, l, mid, L, R, val)
    if R > mid:
        update(o << 1 | 1, mid + 1, r, L, R, val)
    push_up(o);


build(1, 1, n)
ans = 0
for i in range(1, n - k + 2):
    #查询区间[i, i+k-1]的最小值
    mi = query(1, 1, n, i, i + k - 1)
    if mi == 0:                     #无法进行区间消除
        #res表示当前的a[i]
        res = query(1, 1, n, i, i)
        #把当前的a[i]置为0
        update(1, 1, n, i, i, -res)
        ans += res
    else:
        ans += mi
        #区间消除
        update(1, 1, n, i, i + k - 1, -mi)
        #res表示当前的a[i]
        res = query(1, 1, n, i, i)
        #把当前的a[i]置为0
        update(1, 1, n, i, i, -res)
        ans += res
for i in range(n - k + 2, n + 1):
    ans += query(1, 1, n, i, i)
print(ans)

http://lihuaxi.xjx100.cn/news/1274985.html

相关文章

Centos8安装python

#在CentOS 8上安装Python 3 sudo dnf install python3#在CentOS 8上安装Python 2 sudo dnf install python2#设置默认Python版本 python3 sudo alternatives --set python /usr/bin/python3#设置默认Python版本 python2 sudo alternatives --set python /usr/bin/python2

“兆易创新杯”第十八届中国研究生电子设计竞赛有感

今年的电赛给我的感觉是时间真的紧张&#xff0c;可能是因为去年有疫情原因影响所以能准备的时间到七月份&#xff0c;今年不到月底就要全部出成品。我们团队一直在自研一款增强现实眼镜&#xff0c;从硬件设计到软件实现全部由我和另外两个小伙伴一起完成&#xff0c;所以就把…

SpringBoot 插件化开发详细总结

目录 一、前言 1.1 使用插件的好处 1.1.1 模块解耦 1.1.2 提升扩展性和开放性

稀疏表:最大公约数

问题描述 给定一个数组, 每次操作可以选择数组中任意两个相邻的元素 x , y x, y x,y 并将其 中的一个元素替换为 gcd ⁡ ( x , y ) \operatorname{gcd}(x, y) gcd(x,y), 其中 gcd ⁡ ( x , y ) \operatorname{gcd}(x, y) gcd(x,y) 表示 x x x 和 y y y 的最大公约数。 请…

C++之初始化列表

C之初始化列表 在c中&#xff0c;初始化列表可以很大程度的简化参数的赋值&#xff0c;例如 class Student {public:Student();int age;string name;string number; };Student::Student():age(10), name("张三"), number("202310100599") {最近发现C中的…

HackTheBox - 学院【CPTS】复习2 - Pivoting, Tunneling, and Port Forwarding

Pivoting, Tunneling, and Port Forwarding Rpivot Rpivot基于python&#xff0c;一大亮点是反向socks隧道搭建&#xff0c;这将能有效的规避防火墙入站规则 Windows端口转发 - LOL 通过自带的netsh工具可以直接创建端口转发 netsh interface portproxy add v4tov4 listen…

详细讲解接口自动化攻略

目录 前言&#xff1a; 为什么要做接口自动化 问题在哪里 全靠参数化 接口间参数传递 测试数据参数化 测试断言 测试管理 导入测试用例 接口执行顺序 使用测试数据集 测试参数配置 运行结果&测试报告 测试套件 前言&#xff1a; 接口自动化是提高测试效率和…

scrapy学习(scrapy项目学习)

创建scrapy项目 创建爬虫项目 scrapy startproject ss1_miove创建爬虫文件&#xff08;&#xff09; 命令格式&#xff1a;scrapy genspider <爬虫名称> <网站域名> scrapy genspider ss1_scrapy ssr1.scrape.centerscrapy框架的组成 spider文件夹&#xff1a…