题意:给一个序列(n<=500000),要求选定k个不同区间,使得区间长度在L,R之间,并使得k个区间和之和最大,输出这个最大值。

刚拿到题的时候想的是,对于每个点,如果以它开头,那么之后的L-1个一定被选,剩下的R-L个可选,对这一部分进行最大前缀和就好啦!用主席树搞搞,建树的时候维护下就好了。

但有个问题,以这个区间为开头的情况不止一种,这种做法确实能求出以它开头的最大值,那次大值,k大值呢?这也是有可能计入答案的。所以不行。

正解是,对于一个位置,如果我们考虑以它结尾,这个区间等于它的前缀和减去前面一个位置的前缀和,其中位置i满足i离这个位置不小于L不超过R。对于这个位置,我们只需要找这个区间内的区间k大,用这个位置前缀和减掉就好了,然后去求区间k+1大。放入一个堆中取k次就好。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 500005
 4 #define LL long long
 5 inline int read(){
 6     int x=0,f=1; char a=getchar();
 7     while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();}
 8     while(a>='0' && a<='9') x=x*10+a-'0',a=getchar();
 9     return x*f;
10 }
11 LL sum[N];
12 struct data{
13     int num,k;LL val;
14     bool operator < (const data& w)const{
15         return val<w.val;
16     }
17 }t;
18 priority_queue<data>q;
19 namespace Chairman_Tree{
20     int root[N],size;
21     struct ct{
22         int son[2],sz;
23     }tr[20000005];
24     void insert(int x,int& y,LL l,LL r,LL v){
25         y=++size; tr[y].sz=tr[x].sz+1;
26         if(l==r) return;
27         memcpy(tr[y].son,tr[x].son,sizeof(tr[y].son));
28         int mid=(l+r)>>1;
29         if(mid>=v) insert(tr[x].son[0],tr[y].son[0],l,mid,v);
30         else insert(tr[x].son[1],tr[y].son[1],mid+1,r,v);
31     }
32     LL query(int x,int y,LL l,LL r,int k){
33         if(tr[y].sz-tr[x].sz<k) return 1e9;
34         if(l==r) return l;
35         int mid=(l+r)>>1,s=tr[tr[y].son[0]].sz-tr[tr[x].son[0]].sz;
36         if(k<=s) return query(tr[x].son[0],tr[y].son[0],l,mid,k);
37         else return query(tr[x].son[1],tr[y].son[1],mid+1,r,k-s);
38     }
39 }
40 #define CT Chairman_Tree
41 #define L -500000005
42 #define R 500000005
43 int main(){
44     int n=read(),k=read(),l=read(),r=read();
45     LL ans=0; CT::insert(0,CT::root[0],L,R,0);
46     for(int i=1;i<=n;i++) sum[i]=sum[i-1]+read();
47     for(int i=1;i<=n;i++) CT::insert(CT::root[i-1],CT::root[i],L,R,sum[i]);
48     for(int i=l;i<=n;i++){
49         int ri=i-l,le=i-r-1;
50         LL tmp;
51         if(le<0) tmp=CT::query(0,CT::root[ri],L,R,1);
52         else tmp=CT::query(CT::root[le],CT::root[ri],L,R,1);
53         q.push((data){i,1,sum[i]-tmp});
54     }
55     while(k--){
56         t=q.top(); q.pop();
57         ans+=t.val;
58         int ri=t.num-l,le=t.num-r-1; LL tmp;
59         if(le<0) tmp=CT::query(0,CT::root[ri],L,R,t.k+1);
60         else tmp=CT::query(CT::root[le],CT::root[ri],L,R,t.k+1);
61         q.push((data){t.num,t.k+1,sum[t.num]-tmp});
62     }
63     cout<<ans;
64     return 0;
65 }