【洛谷】P1404 平均数

news2024/9/30 3:18:53

【洛谷】P1404 平均数



题目描述

给一个长度为 n n n 的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度 ≥ m \ge m m

输入格式

第一行两个整数 n n n m m m

接下来 n n n 行,每行一个整数 a i a_i ai,表示序列第 i i i 个数字。

输出格式

一个整数,表示最大平均数的 1000 1000 1000 倍,如果末尾有小数,直接舍去,不要用四舍五入求整。

样例输入 #1

10 6
6
4
2
10
3
8
5
9
4
1

样例输出 #1

6500

提示

  • 对于 60 % 60\% 60% 的数据,保证 m ≤ n ≤ 1 0 4 m\le n\le 10^4 mn104
  • 对于 100 % 100\% 100% 的数据,保证 1 ≤ m ≤ n ≤ 1 0 5 1 \leq m\le n\le 10^5 1mn105 0 ≤ a i ≤ 2000 0\le a_i\le2000 0ai2000



题解



题目的要求可细分为两点,一是子序列的均值最大,二是子序列的长度不低于m。在求解时,我们能想到的最直接的方法就是用两重循环来一一枚举该序列的所有子序列,并分别求其均值以寻找最大均值(这里又是一重循环),因此暴力枚举方法的时间复杂度为 O ( n 3 ) O\left(n^3\right) O(n3)。这在题目给出的数据范围下,必定超时无疑。这时候,可能你会马上想到一种数据结构——前缀和(尚不清楚这一数据结构的童鞋请移步学习 ☞ 传送门 ),它的存在可将子段和转化为前缀和相减的形式。但不幸的是,其也只能将上面思路中求每个子序列均值的那重循环降至常数级。因此,采取这样的方法求解的事件复杂度为 O ( n 2 ) O\left(n^2\right) O(n2) ,依然不能拿到满分。

这时候,我们需要另辟奚径地来思考这道题。题目不是要求序列中的最大均值么?我们可以将“查找具有最大均值的子序列”转换为“对于某个值,是否存在某个子序列的均值比它更大”。这一转换非同小可,因为前者(在一个序列中枚举所有子序列)是一个 O ( n 2 ) O\left(n^2\right) O(n2) 的问题,而后者(在一个范围内寻找某个值)是一个 O ( n ) O\left(n\right) O(n) 的问题。更进一步地,对于这种区间寻值的问题,我们似乎很容易想到一种算法思想——分治。于是,我猜你也想到了,二分法。

基于以上分析,可大致将求解思路总结如下:

  1. 确定题目所给数列的均值范围。由于题目给出的数据非负,因此其输入的数列均值最小为 0。对于最大值,可以直接用题目给出的数据范围,也可以用一个寄存器从输入数据中记录输入数列的最大值,并以该值作为此数列的均值上限;
  2. 对1中得到均值上下限,采用二分法进行查找(枚举),每次都对当前的中间值 m i d a v e midave midave 进行判断,判断内容为:当前数列里是否存在一个长度不低于m的子序列,其均值不低于 m i d a v e midave midave?如果是,则将二分法查找的下限置为 m i d a v e midave midave;否则将二分法查找的上限置为 m i d a v e midave midave

最后程序结束时,再将得到的均值乘以 1000 即可。

接下来,我们的问题就变为:如何判断数列里是否存在一个长度不低于 m m m 的子序列,其均值不低于 m i d a v e midave midave?注意到一件事,这里依然需要查找子序列。为了避免重复计算,便考虑构建前缀和数组。但是,我们还要像最开始提到的方式来一一枚举子序列么?如果是,那现在做的思路转换其实并无意义(这就好比你把难的题放到最后做,最终还是逃不掉面对它的那一刻)。如果不是,那要如何求解呢?

再对当前的情况进行一个梳理,现在我们的任务是:对于一个输入的指定值 m i d a v e midave midave,判断给定序列中是否存在长度不低于 m m m 的子序列,其均值大于 m i d a v e midave midave。对于这个问题我们可以做这样的处理:将原序列中的每个数值都减去该均值,对处理后的序列而言,一旦出现某段子序列的总和大于0,就说明该序列对应在原序列部分的元素均值是大于 m i d a v e midave midave的。

在这里插入图片描述

因此,现在我们在拿到 m i d a v e midave midave 时,可对原数列( a r y [   ] ary[\ ] ary[ ])做如下两步处理:

  1. 构建原数列减去 m i d a v e midave midave 后的数列,即: a r y G a p [ i ] = a r y [ i ] − m i d a v e aryGap[i] = ary[i]-midave aryGap[i]=ary[i]midave
  2. 基于新的差值数组构建前缀和数组,即: p r e f i x [ i ] = p r e f i x [ i − 1 ] + a r g [ G a p ] prefix[i] = prefix[i-1]+arg[Gap] prefix[i]=prefix[i1]+arg[Gap]

这样,当我们需要判断某段序列(子区间)的均值是否大于 m i d a v e midave midave 时,实际上就只需要判断当前区间的和是否大于 0。对前缀和数组而言,其仅需要做一次运算和比较,即 p r e f i x [ j ] − p r e f i x [ i ] prefix[j]-prefix[i] prefix[j]prefix[i] 是否大于 0 即可(这里对应的子区间为 [ i + 1 , j ] [i+1,j] [i+1,j] )。于是,这就将问题转换为:判断前缀和序列里,是否存在一个长度不低于 m m m 的间隔,使得位于后面的取值不低于前面。而这个问题简单太多,用一次循环扫描就能得出结论(在循环中记录当前的最小前缀和 m i n G a p minGap minGap,然后每次扫描到一个元素时就判断当前元素的取值是否不低于前面记录的,是则代表目前存在一个满足要求的子序列,否则不存在)。

下面给出基于以上思路得到的完整代码:

/*
    【洛谷】 P1404
*/

#include<bits/stdc++.h> 
using namespace std;

const int MAX = 1e5+5;
int ary[MAX];
double prefix[MAX],eps=1e-8;

// 此函数用于判断:原数组中是否存在长度不低于 m 的子序列,使得其均值大于 thresold 
bool anySeq(int ary[], int n, int m, double thresold){
    double minGap = 0;
    
    // 计算以 thresold 为基准值得到的差值数组的前缀和数组
    for(int i=1;i<=n;i++){
        prefix[i] = prefix[i-1] + (ary[i]-thresold);
        
        // 当 i 不低于 m 时,就能检测子序列的存在情况了
        if(i>=m) {
            minGap = min(minGap, prefix[i-m]);
            
            // 只要该前缀和数组中存在不低于 0 的值,说明一定存在某个序列能使其均值大于 thresold 
            if(prefix[i]>minGap) return true;
        }
    } 
    
    return false; 
}

int main( )
{
    // 录入数据 
    int n,m,maxtmp=-1; cin>>n>>m; 
    
    // 录入原始数组,并记录最大值(该最大值表明此数组能取到的最大平均值即为该值) 
    for(int i=1;i<=n;i++){
        cin>>ary[i];
        maxtmp = max(maxtmp, ary[i]);
    }
    
    // 对最大平均值进行二分查找
    double minave = 0, maxave = maxtmp, midave;
    
    // 这里必须用精度进行控制,否则会超时 
    while(maxave - minave >= eps){
        
        // 设置当前的均值 
        midave = (minave+maxave) / 2;
        
        // 判断当前数组是否存在能大于该平均值的序列(长度不低于 m) 
        if(anySeq(ary, n, m, midave)) minave = midave;
        else maxave = midave;
    } 
    
    // 进行放大后再输出 
    cout<<int(maxave*1000)<<endl;
    
    return 0;
}

END


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/545478.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

激光点云3D目标检测算法之CenterPoint

激光点云3D目标检测算法之CenterPoint 本文首发于公众号【DeepDriving】&#xff0c;欢迎关注。 前言 CenterPoint是CVPR 2021的论文《Center-based 3D Object Detection and Tracking》中提出的一个激光点云3D目标检测与跟踪算法框架&#xff0c;与以往算法不同的是&#xff…

一大波特斯拉人形机器人上线,马斯克震撼官宣2款新车!

来源 | 新智源 ID | AI-era 【导读】这次特斯拉股东日&#xff0c;虽没有新车&#xff0c;但马斯克确定Cybertruck今年一定会来。 特斯拉股东日&#xff0c;依旧没有新车。 万众瞩目的马斯克登台继续画饼&#xff0c;「我不官宣新车&#xff0c;不过新车年销量会超过500万」…

【云原生】k8sPod基础概念

k8sPod基础概念 一、Pod概述1、pod概念2、Pod资源限制 二、Pod的两种使用方式三、资源共享1、创建Pod的方式2、Pod功能 四、底层容器Pause1、Pause共享资源2、Pause主要功能3、Pod与Pause结构设计用意 五、镜像的拉取策略1、Pod容器镜像拉取策略2、Pod重启策略 六、容器的分类1…

信息收集-ip地址

1、cdn网络 CDN&#xff08;Content Delivery Network&#xff09;网络是一种分布式网络架构。它通过将内容&#xff08;如网页、图片、视频等&#xff09;缓存到公共的服务器上&#xff0c;以便更快速、更可靠地交付给用户所在的位置。CDN解决了Internet中的一些固有瓶颈和性…

【ROS】Ubuntu22.04安装ROS2(Humble Hawksbill)

0、版本说明 Ubuntu22.04对应的ROS2的版本为Humble Hawksbill&#xff08;ros-humble&#xff09; 如果不是在Ubuntu22.04中安装ROS&#xff0c;请参考下面Ubuntu和ROS的版本对应关系 1、更新apt包列表 $ sudo apt update2、设置编码 将ubuntu环境语言编码设置为en_US en_…

appium自动化测试实战详解及框架搭建

目录 一、Appium的介绍 二、Appium实战&#xff08;以真机为例&#xff09; 一、Appium的介绍 Appium是一款开源的自动化测试工具&#xff0c;其支持iOS和安卓平台上的原生的&#xff0c;基于移动浏览器的&#xff0c;混合的应用。 1、 使用appium进行自动化测试的好…

【C++】容器篇(一)—— vector 的基本概述以及模拟实现

前言&#xff1a; 在之前&#xff0c;我们已经对 string类进行了基本的概述&#xff0c;并且手动的实现了string类中常用的接口函数。本期&#xff0c;我将带领大家学习的是STL库中的一个容器 -- vector 的学习。相比于之前的string类&#xff0c;本期的 vector 相对来说实现起…

CSAPP复习(三)

CH1: 但是如果问什么时候 得到二进制文件 那就是汇编的时候 CH2 sizeof 的返回值是一个无符号数 然后i-D自动默认是一个无符号数 无符号数不能出现负数 所以出现了一个循环 所以永远不可能循环完成。 CH7链接 什么是静态库&#xff1f;使用静态库的优点是什么&#xff1f; …

在windows内使用virtualbox搭建安卓x86--以及所遇到的问题解决--3

一.ARM兼容包的植入 1.下载arm包: 2.安装arm兼容包 3.验证arm兼容包是否移植成功 二.触屏无效 三.玩游戏卡顿严重 一.ARM兼容包的植入 在AndroidX86系统内大部分应用(国内)并没有适配X86架构&#xff0c;安装基于arm架构的应用会出现报错的情况&#xff0c;如遇到此问题可…

【Linux网络】Linux防火墙

Linux防火墙 一 、Linux包过滤防火墙概述1.1iptables概述1.2netfitel与iptables的关系1.3四表五链1.3.1 四表1.3.2五链1.3.3数据包到达防火墙时&#xff0c;规则表之间的优先顺序**1.3.4规则链之间的匹配顺序** 二、iptables的安装与配置方法2.1iptables的安装2.2iptables的配置…

MySQL数据库基础3-基础查询

文章目录 基础查询(单表)替换查询结果排序筛选分页结果更新表删除数据截断(清空)表聚合函数分组查询 基础查询(单表) 创建表、单行插入、多行插入就不重复介绍了。 替换 当我们的程序每天都会产生大量的数据&#xff0c;而这些数据都是前一天或者再之前的数据更新产生&#…

0基础学习VR全景 平台篇第26章:热点功能-3D物体/空间模型

大家好&#xff0c;欢迎观看蛙色VR官方系列——后台使用课程&#xff01; 本期为大家带来蛙色VR平台&#xff0c;热点功能—3D物体/空间模型操作。 热点&#xff0c;指在全景作品中添加各种类型图标的按钮&#xff0c;引导用户通过按钮产生更多的交互&#xff0c;增加用户的多…

opencv_c++学习(十四)

一、图像直方图的统计与绘制 如果直方图各个数字之间分布比较均衡&#xff0c;则其对比度就相对较低&#xff0c;反之亦然。同时也可以通过直方图可以大致了解图像的亮暗等。 calcHist(const Mat * images, int nimages, const int * channels, lnputArray mask, OutputArray…

【Python Xpath】零基础也能轻松掌握的学习路线与参考资料

Python是一种面向对象的编程语言。Xpath是一种在XML文档中定位信息的方法。XPath是一种语言&#xff0c;可以用于xml和html文档中选择和查找节点。在Python中&#xff0c;我们可以使用xpath来解析html页面&#xff0c;从而提取所需的数据。 Python xpath学习路线&#xff1a; …

C++中的继承、以及赋值兼容转换。

一、继承的概念及定义 继承可以使代码复用&#xff0c;允许在保持原有类特性的基础上进行扩展。 举个例子&#xff1a;就好比我现在要封装老师、学生等这些人的属性和方法&#xff0c;但是这些人都有重复的属性和方法&#xff0c;比如name、age、sex等等&#xff0c;那么我可…

let、const、var的区别,解构赋值,箭头函数

let、const、var的区别 使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象。使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升。使用const声明的是常量,在后面出现的代码块中,不能在修改改常量的值。 var let const 函数级作用域 块级…

Go语言核心编程-运算符和进制转换

第 4 章 运算符 4.1 运算符的基本介绍 运算符是一种特殊的符号&#xff0c;用以表示数据的运算、赋值和比较等 运算符是一种特殊的符号&#xff0c;用以表示数据的运算、赋值和比较等 算术运算符赋值运算符比较运算符/关系运算符逻辑运算符位运算符其它运算符 4.2 算术运算符…

体验联网版 ChatGPT:优点和缺点同样明显,还藏着无限可能

ChatGPT 有点像古希腊的阿喀琉斯&#xff1a;它很强大&#xff0c;却有个致命的弱点——无法联网&#xff0c;这注定了它只能是一个停留在 2021 年的超人。 但很快&#xff0c;我们将等到一个「鱼和熊掌兼得」的时刻。 通过插件集的 Web browsing 功能&#xff0c;ChatGPT 就…

C++每日一练:贝博士的机械零件(补全题目)奇偶排序(巧妙快排)寻因找祖

文章目录 前言一、贝博士的机械零件1、题目2、解法 二、奇偶排序&#xff08;巧用快排&#xff09;三、寻因找祖 前言 今天的题目中寻因找祖最难了&#xff0c;明显的数学题&#xff0c;笔者这数学文盲水平肯定不会&#xff0c;用暴力搞了一波&#xff0c;只有50%。就去考察学…

(二十六)ATP应用测试平台——将一个微服务打包成含skywalking链路追踪的docker镜像

前言 延续前面的章节内容&#xff0c;本节内容我们以ht-atp的springboot应用为例&#xff0c;封装一个包含skywalking链路追踪的微服务docker应用。完成服务调用的链路追踪监控。skywalking采用字节码注入的方式实现代码的无侵入&#xff0c;探针采集数据粒度粗&#xff0c;但…