寻找段落

题目链接

其实我本来只是想做道水题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;
}
原文地址:https://www.cnblogs.com/qwq-/p/14082059.html