最大平均子序列

这道题的大概意思是给出两个数m,n,之后的m行都给出一个整数,让找出一个子序列长度大于等于n,且其平均值最大。这样的水题都要想半天,我好菜啊T^T,菜归菜还是要好好学习的。
分析

这道题的主要思路呢就是转换和二分,将求平均数转换成求和并用二分法逐步缩小最大平均值的范围,
最后当范围缩小至1e-5时即可认为是最大平均值。
首先先找到数组中最大的数max,以max/2为二分开始的起点(我们可以知道平均数一定不会超多最大的数),
那么如何判断平均数的范围呢,那么就要看平均数是怎么求得的,avg=(sum[i]-sum[j])/i-j,其实我们可以认为
平均数是斜率。那么寻找斜率最大(满足要求的)的不就好了吗?m是最短的长度那么寻找的斜率至少得满足条件
i-j>=m,那么找到sum最小的值(在条件范围内)并逐步和满足要求的其余的值进行比较即可,如果寻找过程中找到
平均值大于avg(即(sum[i]-sum[j])/i-j>avg)那么该数组的最大平均值大于avg,就可以缩小二分的范围并继续上一步操作。
反之,如果寻找的没有比avg大的,那么该数组的最大平均值小于avg,也可以缩小二分的范围并继续上一步操作。直到二分的范围缩小到满足误差之后即可停止。

代码
//最长平均子序列
#include <bits/stdc++.h> //万能头文件
using namespace std;
const int MAXN = 1e5;
int arr[MAXN + 5];
double sum[MAXN + 5];
int n, m;

bool check(double avg)
{
    for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + arr[i] - avg;
    double minv = 0;
    for(int i = m; i <= n; ++i) {
        minv = min(minv, sum[i - m]);
        if(sum[i] >= minv) return true;
    }
    return false;
}

int main()
{
    scanf("%d %d", &n, &m);  // cin  cout
    double l = 0, r = 0;
    for(int i = 1; i <= n; ++i) {
        scanf("%d", arr + i);
        r = max(r, double(arr[i]));
    }

    while(r - l > 1e-5) {//二分法
        double mid = (l + r) / 2;
        if(check(mid)) l = mid;
        else r = mid;
    }

    printf("%d\n", int(r * 1000));
    return 0;
}
  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值