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;
}