洛谷 寻找段落

Description

给定一个长度为 n 的序列 a,定义 ai​ 为第 i 个元素的价值。现在需要找出序列中最有价值的“段落”。段落的定义是长度在[S,T] 之间的连续序列。最有价值段落是指平均值最大的段落。

段落的平均值 等于 段落总价值 除以 段落长度

Input

第一行一个整数 n,表示序列长度。

第二行两个整数 S 和 T,表示段落长度的范围,在[S,T] 之间。

第三行到第n+2 行,每行一个整数表示每个元素的价值指数。

Output

一个实数,保留3 位小数,表示最优段落的平均值。

Sample 1

InputcopyOutputcopy
3
2 2
3
-1
2
1.000

AC代码

#include <iostream>  
#define eps 1e-5  // 定义一个很小的数作为二分查找的精度  
using namespace std;  
const int N=1000005;  // 定义数组的最大长度  
  
int n,s,t;  // n为数组长度,s和t为题目要求的区间大小  
int a[N],q[N];  // a为输入的数组,q用于存储滑动窗口中的索引  
double sum[N];  // sum[i]存储从a[1]到a[i]的元素减去mid的累加和  
  
// 检查是否存在一个长度为t的子数组,其和大于等于0  
bool check(double mid){  
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]-mid;  // 计算累加和并减去mid  
    int tail=0,head=1;  // 双端队列,head为队首,tail为队尾  
    for(int i=s;i<=n;i++){  // 从s开始遍历,因为需要s长度的前缀和  
        while(head<=tail&&sum[q[tail]]>sum[i-s]) tail--;  // 维护队列的单调性,保证队尾元素最大  
        q[++tail]=i-s;  // 将新的位置加入队列  
        if(head<=tail&&q[head]<i-t) head++;  // 如果队首元素已经不在当前考虑的t长度范围内,则出队  
        if(head<=tail&&sum[i]-sum[q[head]]>=0) return true;  // 如果当前位置与队首位置的差值(即子数组和)大于等于0,则返回true  
    }  
    return false;  
}  
  
int main(void){  
    cin>>n>>s>>t;  // 输入n, s, t  
    for(int i=1;i<=n;i++) cin>>a[i];  // 输入数组a  
    double l=-10000,r=10000;  // 初始化二分查找的左右边界  
    while(r-l>eps){  // 当二分查找的区间大小大于eps时继续查找  
        double mid=l+(r-l)/2;  // 计算中点  
        if(check(mid)) l=mid;  // 如果存在满足条件的子数组,则调整左边界  
        else r=mid;  // 否则调整右边界  
    }  
    printf("%.3f",l);  // 输出最终的结果,即满足条件的最小子数组和  
    return 0;  
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

j2189259313

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

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

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

打赏作者

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

抵扣说明:

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

余额充值