题意:给一个序列(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 }