[洛谷P1419] 寻找段落

一道单调队列的好题

传送门:>Here<

题意:求一个连续子段,其长度在\([S,T]\)之间,使其平均值最大。保留三位小数

解题思路

考虑二分答案,转化为判定问题。设当前二分到\(k\),则一段满足要求的子序列一定满足:\[\dfrac{a[l]+...+a[r]}{r-l+1} \geq k\]于是变形可得\[a[l]+...+a[r] \geq k*(r-l+1)\]也就等同于\[(a[l]-k)+...+(a[r]-k) \geq 0\]于是我们只需要找出一段进行如上处理的序列中,长度在范围内的非负子序列即可。这个可以通过维护前缀和用单调队列实现

反思

一直没有推到最后一步。依然在判断\[a[l]+...+a[r] \geq k*(r-l+1)\]的子序列的存在问题。事实上这样的判断让二分没有意义了。我们是在找最大的一段a了,跟\(k\)完全没有关系。因为是求平均值,一段和较大的子序列不一定平均值就大了。我们巧妙地通过将\(k\)移项,使平均值问题转化为了求和问题

Code

注意长度有两个范围,所以在\(push\)的时候不是\(push(i)\),而是\(push(i-S)\)

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
    int x = 0; int w = 1; register char c = getchar();
    for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
} 
int N,S,T;
double L,R,Mid,Ans;
int q[MAXN],a[MAXN];
double sum[MAXN];
inline bool judge(double k){
    for(int i = 1; i <= N; ++i){
        sum[i] = sum[i-1] + a[i] - k;
    }
    int h = 1, t = 1;
    q[1] = 0;
    for(int i = S; i <= N; ++i){
        while(h <= t && q[h] < i-T) ++h;
        if(i-S > 0){
            while(h <= t && sum[q[t]] >= sum[i-S]) --t;
            q[++t] = i-S;   
        }
        if((i-q[h]>=S && i-q[h]<=T) && sum[i]-sum[q[h]] >= 0) return 1;
        
    }
    return 0;
}
int main(){
//  freopen(".in","r",stdin);
    N = read(), S = read(), T = read();
    for(int i = 1; i <= N; ++i){
        a[i] = read();
        sum[i] = sum[i-1] + a[i];
    }
    L = -10000.00, R = 10000.00;
    while(R - L >= 1e-5){
        Mid = (L + R) / 2.0;
        if(judge(Mid)){
            L = Mid;
            Ans = Mid;
        }
        else{
            R = Mid;
        }
    }
    printf("%.3f", Ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qixingzhi/p/9892959.html