將序列之和轉化爲\(sum[r]-sum[l-1]\),固定右端點,左端取最大值
用堆丟出一個丟進兩個就好了,c++
#include<bits/stdc++.h> using namespace std; const int N=5e5+6,M=20; int n,k,L,R,t,mi[M],lg[N],f[N][M],g[N][M],sum[N]; long long ans=0; struct xd{ int l,r,x,y; bool operator < (const xd &a) const {return sum[x]-sum[y-1]<sum[a.x]-sum[a.y-1];} }tmp,nw; priority_queue<xd> q; inline int read(){ int T=0,F=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();} while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar(); return F*T; } void st(int l,int r,xd &p){ int h=lg[r-l+1]; p.l=l,p.r=r; p.x=(f[l][h]>f[r-mi[h]+1][h]?g[l][h]:g[r-mi[h]+1][h]); } int main(){ n=read(),k=read(),L=read(),R=read(),mi[0]=1,lg[0]=-1; for(int i=1;i<=n;++i) t=read(),sum[i]=sum[i-1]+t,f[i][0]=sum[i],g[i][0]=i,lg[i]=lg[i>>1]+1; for(int i=1;i<=19;++i) mi[i]=mi[i-1]*2; for(int i=1;i<=19;++i) for(int j=1;j+mi[i]-1<=n;++j) f[j][i]=max(f[j][i-1],f[j+mi[i-1]][i-1]),g[j][i]=(f[j][i-1]>f[j+mi[i-1]][i-1]?g[j][i-1]:g[j+mi[i-1]][i-1]); for(int i=1;i<=n;++i) if(i+L-1<=n) st(i+L-1,min(i+R-1,n),tmp),tmp.y=i,q.push(tmp); while(!q.empty()&&k--){ tmp=q.top(),q.pop(),ans+=1ll*(sum[tmp.x]-sum[tmp.y-1]); if(tmp.l<=tmp.x-1) nw.y=tmp.y,st(tmp.l,tmp.x-1,nw),q.push(nw); if(tmp.r>=tmp.x+1) nw.y=tmp.y,st(tmp.x+1,tmp.r,nw),q.push(nw); } printf("%lld\n",ans); return 0; }