HDU 2993 MAX Average Problem

MAX Average Problem

HDU 2993

题意:给你一个长度为n的数列,求长度大于等于k的区间的最大平均值。

注意,此题卡读入。。。珍爱生命,使用fread

方法1:求斜率最大值,维护下凸

1.定义sum[i]为前缀和。每个点为(i,sum[i])

2.求(sum[i]-sum[j])/(i-j)的最大值,即求k(i,j)的最大值。

3.在已有的下凸单调队列中找到第一个

(sum[q[l+1]]-sum[q[l]])/(q[l+1]-q[l])>(sum[i]-sum[q[l]])/(q[l+1]-q[l])

因为斜率都是递增的,一定会有解

方法2:二分答案

1.答案保留两位小数,精度不是很大,二分的答案精度稍大与两位即可。

2.二分答案后把每个数减去二分出的答案,问题转化成寻找长度>=K的连续和非负

3.定义:sum[i]为减去二分答案后的前缀和。

res=max(sum[i]-sum[j])(i-j>=K)->
res=max(sum[i]-min(sum[j]))
枚举每个i,同时移动j,维护sum[j]的最小值。
O(n)求出res
判断res是否非负

方法一:斜率优化。代码入下:

#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
int tot;
const int BUF=25000000;
char Buf[BUF],*buf=Buf;
void rd(int &a) {
    for(a=0; *buf<48; buf++);
    while(*buf>47)a=a*10+*buf++-48;
}
int n,K,sum[M];
int q[M],l,r;
int main() {
    tot=fread(Buf,1,BUF,stdin);
    while(1) {
        if(buf-Buf+1>=tot)break;
        rd(n),rd(K);
        for(int i=1; i<=n; i++) {
            rd(sum[i]);
            sum[i]+=sum[i-1];
        }
        q[l=r=1]=0;
        double ans=0;
        for(int i=K; i<=n; i++) {
            while(l<r&&1ll*(sum[q[l+1]]-sum[q[l]])*(i-q[l])<=1ll*(q[l+1]-q[l])*(sum[i]-sum[q[l]]))l++;
            ans=max(ans,1.0*(sum[i]-sum[q[l]])/(i-q[l]));
            int j=i-K+1;
            while(l<r&&1ll*(sum[q[r]]-sum[q[r-1]])*(j-q[r])>=1ll*(q[r]-q[r-1])*(sum[j]-sum[q[r]]))r--;
            q[++r]=j;
        }
        printf("%.2f\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值