【解题报告】洛谷P1419 寻找段落
【解题报告】洛谷P1419 寻找段落
题目链接
https://www.luogu.com.cn/problem/P1419
思路
这道题目我们首先可以想暴力,我们暴力的时候记录一个前缀和
时间复杂度 \(O(n^2)\)
然后我们考虑优化
我们要找到的是一个最大的平均区间,我们发现,区间长度越小,实际上,得到最大的平均值越大的概率越高,所以我们可以设置一个时间,然后在快要超时的时候直接退出,返回一个暂时的最优解,虽然时间复杂度没改变,还是能通过这一道题目
但是我们当然要正统方法
通过前面的分析可以知道,我们可以二分一个区间的平均值,然后判断这个平均值能不能达到,如果可以达到的话则试更大的平均值,反之,试更小的平均值
然后二分之内的判断函数实际上就是要找是否存在一个序列,使得这个序列的和大于 \(0\)
我们可以使用单调队列来维护是否存在这样一个连续的序列
总共的时间复杂度 \(O(nlogn)\)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <ctime>
using namespace std;
const int maxn=100005;
int s,t;
int n;
double a[maxn],b[maxn];
double mx=-1e9;
double ans;
bool check(double x)
{
for(int i=1;i<=n;i++)
b[i]=b[i-1]+1.0*a[i]-x;
int head=1,tail=0;
int q[maxn];
for(int i=s,j=0;i<=n;i++,j++)
{
while(head<=tail&&b[q[tail]]>b[j]) tail--;
q[++tail]=j;
while(head<=tail&&i-q[head]>t) head++;
if(b[i]-b[q[head]]>0.00001) return true;
}
return false;
}
int main()
{
cin>>n;
cin>>s>>t;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=b[i-1]+a[i];
mx=max(mx,1.0*a[i]);
}
double l=-10000,r=10000;
while(l<=r-0.00001)
{
double mid=(l+r)/2.0;
if(check(mid))
l=mid,ans=l;
else
r=mid;
}
printf("%.3lf\n",ans);
return 0;
}
本博文为wweiyi原创,若想转载请联系作者,qq:2844938982