• 洛谷P3594 [POI2015]WIL-Wilcze doły


    题面

    传送门

    分析

    一道较为简单的单调队列题目

    思路和上一道题很像,就是枚举右端点,然后找到满足条件的“最左”的左端点

    怎么找呢,我们发现随着右端点的右移,其实左端点也在不断地右移,那么就是左端点单调不减

    然后我们就可以想到单调队列来维护了

    队列当中维护的信息是什么呢...

    左端点位置?不是。

    因为这样维护的话我们每次还要在当前区间当中找到最大的长度为(d)的区间,很麻烦

    所以我们直接维护这个长度为(d)的区间的和的最大值,以及这个区间的左端点即可(就是说队列里存的是这个区间和的最大值对应区间的位置,而且在这个过程中,我们顺带记一下左端点(st)的位置)

    然后总复杂度就是(O(n))的,具体细节看代码

    代码

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define ll long long
    const int N=2e6+5;
    ll n,p,d,hh,tt=-1,que[N],a[N],pre[N],val[N],st=1,ans; 
    int main(){
    	read(n),read(p),read(d);
    	for(int i=1;i<=n;i++) read(a[i]);
    	for(int i=1;i<=n;i++) pre[i]=pre[i-1]+a[i];
    	for(int i=d;i<=n;i++) val[i]=pre[i]-pre[i-d];
    	que[++tt]=d,ans=d;
    	for(int i=d+1;i<=n;i++){
    		while(hh<=tt&&val[i]>val[que[tt]]) tt--;//维护最大的长度为$d$的区间
    		que[++tt]=i;
    		while(hh<=tt&&pre[i]-pre[st-1]-val[que[hh]]>p) st++;
                    while(hh<=tt&&que[hh]-d+1<st) hh++;//如果本身这个最大值已经不在当前$st-i$的区间内,直接弹出
    		ans=max(ans,i-st+1);
    	}
    	write(ans);
    	return 0;
    }
    
  • 相关阅读:
    《你的灯还亮着吗?》读后感(一)
    课堂练习-找水王
    私人助手-典型用户和场景描述
    课堂练习-哈利波特
    战略会议2
    战略会议总结
    "私人助手"NABCD分析
    返回一个首尾相连的二维数组的最大子数组的和
    返回一个首尾相连的一位数组中最大子数组的和
    5个常用Java代码混淆器 助你保护你的代码
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14125495.html
Copyright © 2020-2023  润新知