zoukankan      html  css  js  c++  java
  • [洛谷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;
    }
    
  • 相关阅读:
    event.srcElement就是指向触发事件的元素,他是什么就有什么的属性
    HTML title属性换行显示的方法
    O(∩_∩)O哈哈~
    练习题 英文正常语句倒序书写,标点位置不变
    累了就请休息一下。。。
    给自定义用户控件传递参数
    repeater做成gridview【更新删除编辑等】
    【公众号系列】12306购票送温暖
    【公众号系列】超详细SAP HANA JOB全解析
    【公众号系列】浅谈SAP项目管理的技能
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9892959.html
Copyright © 2011-2022 走看看