单调栈:「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; }

浙公网安备 33010602011771号