其实我本来只是想做道水题QAQ
首先这个题,找连续子区间最大什么的,很想用单调队列
回忆一下板子,求连续子区间最大和
每次从队尾加一个数,如果队列里的和小于0就全弹掉,同时在每次操作后都更新最大值
本题求平均值最大,类比一下,当队列里的平均值小于某个数就弹掉
结合一下数据范围可以二分一下标准
然后因为本题对序列长度有要求
当长度小于最小要求S时,不操作
当长度大于最大要求T时,把队首多出来的全弹掉
当长度大于等于S小于等于T时可以更新答案
但是要不要弹呢?
根据单调队列的思想,可以判断多余S的部分的平均值是否大于标准,小于就全弹掉
这一部分相当于没有长度的要求,可以保证这样做得到的是这部分的最大值
#include<bits/stdc++.h>
using namespace std;
int n,st,ed,line[500000],s[500000],a[500000];
double eps=1e-5;//这里不要忘了开double
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;//注意输入有负数
ch=getchar();
}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return f*x;
}
int check(double ave)
{
int head=1,tail=0;
for(int i=1;i<=n;i++)
{
line[++tail]=a[i];
s[tail]=s[tail-1]+a[i];//前缀和
if((tail-head+1>st)&&s[tail-st]-s[head-1]<ave*(tail-st-head+1)) head=tail-st+1;
if(tail-head+1>ed) head=tail-ed+1;
if(tail-head+1>=st&&tail-head+1<=ed&&(double)(s[tail]-s[head-1])/(double)(tail-head+1)>=ave) return 1;
//如上说述
}
return 0;
}
int main()
{
n=read(),st=read(),ed=read();
int minn=0x3f3f3f3f,maxn=-0x3f3f3f3f;
for(int i=1;i<=n;i++) a[i]=read(),minn=min(minn,a[i]),maxn=max(maxn,a[i]);
double l=minn,r=maxn;
while(l+eps<r)
{
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}//long double不能处理负数
//作为实数范围内二分的板子吧
printf("%.3lf",l);//保留三位小数
return 0;
}