题目描述

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

输入格式

第一行两个整数 $n$ 和 $m$。

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

输出格式

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

输入输出样例

输入 #1

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

输出 #1

6500

说明/提示

  • 对于 $60\%$ 的数据,保证 $m\le n\le 10^4$
  • 对于 $100\%$ 的数据,保证 $1 \leq m\le n\le 10^5$,$0\le a_i\le2000$。

分析

显然这是一个“最小值最大”的问题,所以我们要通过二分来枚举平均值,再寻找字段和较大的字段,代入平均值判断是否成立,不成立则将右端向左,成立则将左端向右,使两个端点不断相互逼近最优解即可得到答案。

代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
double a[100001],sum[100001],b[100001];
double eps=1e-5,l=-1e6,r=1e6;
double min(double x,double y){
    if(x>y)return y;else return x;
}
double max(double x,double y){
    if(x<y)return y;else return x;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    while(r-l>eps){
        double mid = (l+r)/2;
        double maxx=-1e10,minn=1e10;
        for(int i=1;i<=n;i++)b[i]=a[i]-mid;
        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+b[i];
        for(int i=m;i<=n;i++){ 
            minn=(double)min(minn,sum[i-m]);
            maxx=(double)max(maxx,sum[i]-minn);
        }
        if(maxx>0)l=mid;else r=mid;
    }
    cout<<int(r*1000);
    return 0;
} 
最后修改:2021 年 07 月 05 日 09 : 07 PM
如果觉得我的文章对你有用,请随意赞赏