单调栈:「LCOI2021」Low Complexity Round I 新春欢乐赛 T213446 [LCOI RI]Cow Insertion

打开洛谷发现有场进行中的比赛,结果A题就做半天

原题传送门

题面:n个数a1,a2...an,给你个k插进去变成a1,a2,...,k,...,an(最前面和最后面也可以插),给你个m求所有连续m个数的最大值的和,问这个和最大是多少

一开始用线段树弄半天,先是7-8个点TLE,然后各种卡常优化又是register又是快读又是++i最后还是有两个点无论如何都TLE

点开排行榜发现洛谷居然可以看别人的运行时间,好家伙别人都是100多ms,那肯定是O(n)的了

后来思考:区间最大值,但这个区间是固定值,固定为m和m-1,好像可以用一种方法做(后来才知道叫单调栈)

顺便复习(现学)了一下双端队列deque,就两边进出的队列来当单调栈用:

d.push_back(1); d.push_front(2); d.back()==1; d.front()==2; d.pop_back(); d.pop_front();

删了三十行线段树,单调栈几行就ac了

#include<bits/stdc++.h>
using namespace std;
const int maxn=5000010;
int a[maxn+2],b1[maxn],b2[maxn];
template <typename T> inline void read(T& x) {
    x=0;T f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=x*f;
    return;
}
template <typename T,typename ...Arg>void read(T& x,Arg& ...arg){
    read(x);
    read(arg...);
}
template <typename T>inline void write(T x) {
    if(x<0)putchar('-'),x=-x;
    if(x<10)putchar(x+'0');
    else write(x/10),putchar(x%10+'0');
}
template <typename T,typename ...Arg>void write(T& x,Arg& ...arg){
    write(x);
    putchar(' ');
    write(arg...);
}
int main(){
    int n,m,q,x,y,z,k,j,ans(0),mans;
    read(n,m,k);
    deque<int> d,p;
    for(register int i=1;i<=n;++i){
        read(a[i]);
        while(d.size()>0&&a[i]>d.back()){d.pop_back();p.pop_back();}
        d.push_back(a[i]);p.push_back(i);
        if(i-m+1>p.front()){
            p.pop_front();d.pop_front();
        }
        if(i-m+1>=1) b1[i-m+1]=d.front();
    }
    m--;
    deque<int> d2,p2;
    for(register int i=1;i<=n;++i){
        while(!d2.empty()&&a[i]>d2.back()){d2.pop_back();p2.pop_back();}
        d2.push_back(a[i]);p2.push_back(i);
        if(i-m+1>p2.front()){
            p2.pop_front();d2.pop_front();
        }
        if(i-m+1>=1) b2[i-m+1]=d2.front();
    }m++;
       ans+=max(b2[1],k);
    for(register int i=1;i<=n-m+1;++i){
        ans+=b1[i];
    }
    mans=ans;
    for(register int i=2;i<=n+1;++i){
//        cout<<ans<<endl;
        if(i+m-1<=n+1){
            ans-=b1[i-1];
            if(k>b2[i])ans+=k;else ans+=b2[i];
        }
        j=i-m;
        if(j>=1){
            if(k>b2[j])ans-=k;else ans-=b2[j];
            ans+=b1[j];
        }
        if(ans>mans)mans=ans;
    }
    cout<<mans<<endl;
    return 0;
}

 

posted @ 2022-01-29 23:56  遥望未来weilai  阅读(59)  评论(0)    收藏  举报