当前位置: 首页 > news >正文

第十三届蓝桥杯省赛 Java A 组 I 题、Python A 组 I 题、Python B 组 J 题——最优清零方案(AC)

1.最优清零方案

1.题意描述

给定一个长度为 N N N 的数列 A 1 , A 2 , ⋯ , A N A_1,A_2,⋯,A_N A1,A2,,AN 。现在小蓝想通过若干次操作将 这个数列中每个数字清零。
每次操作小蓝可以选择以下两种之一:

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

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

2.输入格式

输入第一行包含两个整数 N N N K K K
第二行包含 N N N 个整数 A 1 , A 2 , ⋯ , A N A_1,A_2,⋯,A_N A1,A2,,AN

3.输出格式

输出一个整数表示答案。

4.样例输入

4 2
1 2 3 4

5.样例输出

6

6.数据范围

1 ≤ K ≤ N ≤ 1000000 , 0 ≤ A i ≤ 1000000 。 1≤K≤N≤1000000,0≤A_i ≤1000000 。 1KN1000000,0Ai1000000

7.原题链接

最优清零方案

2.解题思路

比较直观地思考,如果没有操作2,那么总操作次数则是数组的总和。对于答案来说操作2一定是不差于操作1的,为了使操作次数更少,我们应该尽可能多使用操作2

所以问题转化为我们对数组最多能进行几次操作2?答案即是操作2的次数加上剩下数组的总和。

对于一段区间 [ l , r ] [l,r] [l,r],它能进行操作的次数应当是该区间内的最小值 m i mi mi,然后我们需要将区间 [ l , r ] [l,r] [l,r] 所有数都减去 m i mi mi。由于需要去考虑每一个长度为 K K K 的连续子数组,显然我们需要使用到滑动窗口去解决问题。

从贪心的角度思考,我们从左往右进行窗口滑动,统计操作2可进行的最大次数。

对于每一个长度为 K K K 的区间 [ l , r ] [l,r] [l,r] 如果我们都手动去遍历得到 m i mi mi 以及手动减去 m i mi mi,在极限数据下且 k = n / 2 k=n/2 k=n/2时,复杂度会是 O ( n 2 ) O(n^2) O(n2)所以会超时。

考虑如何优化,假设此时枚举的窗口的起点为 l l l,那么终点为 l + k − 1 l+k-1 l+k1,设区间 [ l , r ] [l,r] [l,r] 的最小值的下标为 t ( t ∈ [ l , r ] ) t(t\in[l,r]) t(t[l,r]),如果按照正常滑动窗口,我们下一次窗口枚举的起点为 l + 1 l+1 l+1,但由于操作2要求区间全部数一定大于0。显然 a [ t ] a[t] a[t] 在减去 m i mi mi之后的值一定为0,意味着区间内包含下标t一定不可能再进行操作2,我们可以将下一次窗口枚举的起点设为t+1,以此完成优化,减少无效窗口的枚举次数。

值得注意一点的是一个区间 [ l , r ] [l,r] [l,r]可能同时有多个最小值下标 t t t,我们应当选择最右边的一个。

3.Ac_code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s);
#define SZ(s) ((int)s.size());
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 200010;

int n, k;
void solve()
{
    std::cin >> n >> k;
    std::vector<int> a(n);
    LL ans = 0;
    for (auto&v : a) {
        cin >> v;
    }
    for (int i = 0; i + k - 1 < n; ++i) {
        int t = 0;
        int mi = 1e9;
        for (int j = i; j < i + k; ++j) {
            if (a[j] <= mi) {
                t = j;
                mi = a[j];
            }
        }
        ans += mi;
        for (int j = i; j < i + k; ++j) a[j] -= mi;
        i = t + k - 1;
    }
    for (auto v : a) ans += v;
    cout << ans << '\n';
}
int main()
{
    ios_base :: sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int t = 1;
    while (t--)
    {
        solve();
    }
    return 0;
}

相关文章:

  • 阿里“云开发“小程序(uniCould)
  • 提权漏洞和域渗透历史漏洞整理
  • 传参的理解
  • 基于蜣螂算法的极限学习机(ELM)分类算法-附代码
  • 主流的操作系统(带你快速了解)
  • 六、numpy拷贝
  • STM32+python产生三角波
  • 【计算机网络(考研版)】第一站:计算机网络概述(一)
  • C++空间命名
  • 树,堆,二叉树的认识
  • 计算机存储系统
  • 返回值的理解
  • 前同事居然因为 Pycharm 的这个功能,即使离职三年也依然经常被请去喝茶~
  • IPV4地址详解
  • ubuntu 22.04学习笔记
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • Date型的使用
  • Fastjson的基本使用方法大全
  • Java反射-动态类加载和重新加载
  • Linux Process Manage
  • Lucene解析 - 基本概念
  • Python_OOP
  • Python_网络编程
  • React Transition Group -- Transition 组件
  • TypeScript实现数据结构(一)栈,队列,链表
  • Xmanager 远程桌面 CentOS 7
  • 关于extract.autodesk.io的一些说明
  • 如何用vue打造一个移动端音乐播放器
  • 我感觉这是史上最牛的防sql注入方法类
  • 我是如何设计 Upload 上传组件的
  • 学习JavaScript数据结构与算法 — 树
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • #android不同版本废弃api,新api。
  • (1)(1.11) SiK Radio v2(一)
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (k8s中)docker netty OOM问题记录
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (十五)使用Nexus创建Maven私服
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .net core 连接数据库,通过数据库生成Modell
  • .NET 反射的使用
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .NETCORE 开发登录接口MFA谷歌多因子身份验证
  • .NET建议使用的大小写命名原则
  • @PreAuthorize注解
  • @value 静态变量_Python彻底搞懂:变量、对象、赋值、引用、拷贝
  • [ 手记 ] 关于tomcat开机启动设置问题
  • []新浪博客如何插入代码(其他博客应该也可以)
  • [android] 切换界面的通用处理
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [APUE]进程关系(下)