当前位置: 首页 > 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;
    }
    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;
}

相关文章:

  • 第十三届蓝桥杯省赛 Java A 组 I 题、Python A 组 I 题、Python B 组 J 题——最优清零方案(AC)
  • python图像处理(图像缩放)
  • 2023需要重点关注的四大AI方向
  • 【BTC】数据结构
  • C语言深度解剖-关键字(2)
  • 【二叉搜索树】BST相关题目
  • 济人药业更新招股书:计划在A股上市,中成药业务收入持续下滑
  • 哪里可以找到电子版的大学课本?
  • 数据结构 第三章 栈和队列(队列)
  • 自制DAPLink 基于ARM官方源码以及STM32F103C8T6
  • 极限存在准则 两个重要极限——“高等数学”
  • 【二叉树】java实现代码,详解二叉树,带大家更深刻的掌握二叉树递归思想
  • VMWare 移动Linux CentOS 7虚拟机后连不上网怎么办
  • Opencv调参神器——trackBar控件
  • 打工人必知必会(三)——经济补偿金和赔偿金的那些事
  • 零基础学JavaWeb开发(二十六)之 nginx(2)
  • Bug:SpringBoot类文件具有错误的版本 61.0, 应为 52.0
  • 【Quicker】您的指尖工具箱
  • Python---学生管理系统(pyinstaller)
  • java多线程的使用