【解题报告】洛谷P1419 寻找段落
题目链接
https://www.luogu.com.cn/problem/P1419
思路
这道题目我们首先可以想暴力,我们暴力的时候记录一个前缀和
时间复杂度 O(n2)
然后我们考虑优化
我们要找到的是一个最大的平均区间,我们发现,区间长度越小,实际上,得到最大的平均值越大的概率越高,所以我们可以设置一个时间,然后在快要超时的时候直接退出,返回一个暂时的最优解,虽然时间复杂度没改变,还是能通过这一道题目
但是我们当然要正统方法
通过前面的分析可以知道,我们可以二分一个区间的平均值,然后判断这个平均值能不能达到,如果可以达到的话则试更大的平均值,反之,试更小的平均值
然后二分之内的判断函数实际上就是要找是否存在一个序列,使得这个序列的和大于 0
我们可以使用单调队列来维护是否存在这样一个连续的序列
总共的时间复杂度 O(nlogn)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #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; }
|