首先用前缀和 o1 地维护区间和
对于每个序列尾 将将满足长度的序列的最大值放入优先队列里 然后每次弹出一个 将 该尾部的序列的这个的前驱放入优先队列 重复k次即可
用主席树来维护即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// const int N=1e6+100; int T[N<<5],lson[N<<5],rson[N<<5],ncnt,t[N<<5]; void upnode(int x,int l,int r,int pre,int &pos) { pos=++ncnt; t[pos]=t[pre]+1;lson[pos]=lson[pre];rson[pos]=rson[pre]; if(l==r)return ;int m=(l+r)>>1; if(x<=m)upnode(x,l,m,lson[pre],lson[pos]); else upnode(x,m+1,r,rson[pre],rson[pos]); } int qk(int k,int l,int r,int pre,int pos) { int x=t[lson[pos]]-t[lson[pre]]; if(l==r)return l;int m=(l+r)>>1; if(k<=x)return qk(k,l,m,lson[pre],lson[pos]); else return qk(k-x,m+1,r,rson[pre],rson[pos]); } struct node { int v,k,pos; bool operator<(const node &b)const { return v<b.v; } }; priority_queue<node>q; int a[N],L,R,k,n,s[N]; int main() { scanf("%d%d%d%d",&n,&k,&L,&R); n++;//空出一位0 方便前缀和 rep(i,2,n) { scanf("%d",&a[i]); a[i]+=a[i-1];s[i]=a[i]; } sort(s+1,s+1+n); int nn=unique(s+1,s+1+n)-s-1; rep(i,1,n)a[i]=lower_bound(s+1,s+1+nn,a[i])-s; rep(i,1,n)upnode(a[i],1,nn,T[i-1],T[i]); rep(i,L+1,n) { node x;x.k=1;x.pos=i; x.v=s[a[i]]-s[qk(1,1,nn,T[max(0,i-R-1)],T[i-L] )]; q.push(x); } ll ans=0; while(k--) { node u=q.top();q.pop(); ans+=u.v; if(u.k==min(R-L+1,u.pos-L))continue; u.k++; u.v=s[a[u.pos]]-s[qk(u.k,1,nn,T[max(0,u.pos-R-1)],T[max(0,u.pos-L)])]; q.push(u); } cout<<ans; return 0; }