当我们已经确定了所选区间的右端点,我们可以将区间和转变为前缀相减的形式,然后求[l,r]的最大值也就是求s[r]-s[l-1]的最大值,因为r确定,而l只能在一段固定的区间,我们就RMQ了。然后我们对于每个可行的右端点都找出最优的左端点,把它们扔到优先队列里一个一个取出来就行了,很容易避免删除操作,因为加入原来x的左端点可以在[a,b]中选择,我们与其从[a,b]中去掉y,不如将[a,b]分裂成[a,y-1]和[y+1,b]两段,然后将这两段都扔到优先队列中。也就是说,我们在优先队列中存放的其实是一个四元组(sum,x,a,b),分别代表区间和,右端点,合法左端点的区间最左边和最右边。然后贪心去搞就AC。
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=500005;
int sum[maxn];
int n,k,L,R;
long long ans;
struct data{
int i,l,r,t;
data(){}
data(int _i,int _l,int _r,int _t){
i=_i,l=_l,r=_r,t=_t;
}
bool operator < (const data &rhs)const{
return sum[t]-sum[i-1]<sum[rhs.t]-sum[rhs.i-1];
}
};
priority_queue<data>que;
int f[maxn][20];
void rmq_init(){
for(int i=1;i<=n;i++)f[i][0]=i;
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++){
int x=f[i][j-1],y=f[i+(1<<(j-1))][j-1];
f[i][j]=sum[x]>sum[y]?x:y;
}
}
int rmq(int l,int r){
int k=0;
while((1<<(k+1))<=r-l+1)k++;
int x=f[l][k],y=f[r-(1<<k)+1][k];
return sum[x]>sum[y]?x:y;
}
void solve(){
ans=0;
for(register int i=1;i<=n;i++)if(i+L-1<=n){
int t=min(n,i+R-1);
que.push(data(i,i+L-1,t,rmq(i+L-1,t)));
}
while(k--){
data cur=que.top();que.pop();
ans+=sum[cur.t]-sum[cur.i-1];
if(cur.t-1>=cur.l)que.push(data(cur.i,cur.l,cur.t-1,rmq(cur.l,cur.t-1)));
if(cur.t+1<=cur.r)que.push(data(cur.i,cur.t+1,cur.r,rmq(cur.t+1,cur.r)));
}
}
template<class T>inline void read(T &res){
static char ch;T flag=1;
while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;
}
int main(){
read(n),read(k);read(L),read(R);
for(register int i=1;i<=n;i++)read(sum[i]);
for(register int i=1;i<=n;i++)sum[i]+=sum[i-1];
rmq_init();
solve();
cout<<ans<<endl;
return 0;
}