题目:BZOJ2006.
题目大意:给定一个长度为
n
n
n的序列
a
a
a,现在要求找
k
k
k个满足长度在
[
l
,
r
]
[l,r]
[l,r]内的子段,输出最大的子段和之和.
1
≤
n
,
k
≤
5
∗
1
0
5
,
1
≤
L
≤
R
≤
n
,
−
1
0
3
≤
a
i
≤
1
0
3
1\leq n,k\leq 5*10^5,1\leq L\leq R\leq n,-10^3\leq a_i\leq 10^3
1≤n,k≤5∗105,1≤L≤R≤n,−103≤ai≤103.
首先,肯定是取最大的 k k k个子段之和最优.
考虑 k = 1 k=1 k=1时,很容易想到枚举每一个子段的左端点,并找到使得子段和最大的右端点求出和,在这些和中取最大就是答案,找最大可以用前缀和+ST表实现.
考虑
k
=
2
k=2
k=2时,显然在
k
=
1
k=1
k=1时取完一个子段
[
i
,
p
]
[i,p]
[i,p]后,还有一个次大的必然只有两种情况:
1.在剩下的
k
=
1
k=1
k=1的候选答案中选取.
2.左端点为
i
i
i,右端点在
[
i
+
l
−
1
,
p
−
1
]
[i+l-1,p-1]
[i+l−1,p−1]或
[
p
+
1
,
i
+
r
−
1
]
[p+1,i+r-1]
[p+1,i+r−1].
显然我们可以分别把第二种情况的右端点两种情况的最大值分别放入候选集合,然后取最大.
当 k > 2 k>2 k>2时,我们可以类比这种处理方法,维护一个候选集合,每次取完一个后删掉,并放入删掉的答案会产生的另外两个候选答案.
显然候选集合可以用堆来维护,候选集合大小不会超过 O ( n + k ) O(n+k) O(n+k).具体来说可以维护一个五元组 ( s t , l , r , m x , p ) (st,l,r,mx,p) (st,l,r,mx,p)表示左端点为 s t st st,右端点在区间 [ l , r ] [l,r] [l,r]中,最大值为 m x mx mx,且此时右端点为 p p p.
每次从候选集合中删去一个五元组 ( s t , l , r , m x , p ) (st,l,r,mx,p) (st,l,r,mx,p),就可以放入另外两个五元组 ( s t , l , p − 1 , m x 1 , p 1 ) (st,l,p-1,mx_1,p_1) (st,l,p−1,mx1,p1)和 ( s t , p + 1 , r , m x 2 , p 2 ) (st,p+1,r,mx_2,p_2) (st,p+1,r,mx2,p2).
时间复杂度 O ( ( n + k ) log n ) O((n+k)\log n) O((n+k)logn).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=500000,C=20;
int n,m,l,r,a[N+9];
int mx[N+9][C],p[N+9][C],lg[N+9];
void Pre_doubly(){
for (int i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
for (int i=1;i<=n;++i) mx[i][0]=a[i],p[i][0]=i;
for (int i=1;i<C;++i){
int t=1<<i-1;
for (int j=1;j+t<=n;++j)
if (mx[j][i-1]>=mx[j+t][i-1])
mx[j][i]=mx[j][i-1],p[j][i]=p[j][i-1];
else mx[j][i]=mx[j+t][i-1],p[j][i]=p[j+t][i-1];
}
}
int Query_p(int L,int R){
int t=lg[R-L+1];
return mx[L][t]>=mx[R-(1<<t)+1][t]?p[L][t]:p[R-(1<<t)+1][t];
}
struct state{
int st,l,r,mx,p;
state(int St=0,int L=0,int R=0,int Mx=0,int P=0){st=St;l=L;r=R;mx=Mx;p=P;}
bool operator < (const state &p)const{return mx<p.mx;}
};
priority_queue<state>q;
LL ans;
Abigail into(){
scanf("%d%d%d%d",&n,&m,&l,&r);
for (int i=1;i<=n;++i){
scanf("%d",&a[i]);
a[i]+=a[i-1];
}
}
Abigail work(){
Pre_doubly();
for (int i=1;i+l-1<=n;++i){
int tl=i+l-1,tr=min(i+r-1,n),tp=Query_p(tl,tr);
q.push(state(i,tl,tr,a[tp]-a[i-1],tp));
}
for (int i=1;i<=m;++i){
state t=q.top();q.pop();
ans+=(LL)t.mx;
if (t.p^t.l){
int tp=Query_p(t.l,t.p-1);
q.push(state(t.st,t.l,t.p-1,a[tp]-a[t.st-1],tp));
}
if (t.p^t.r){
int tp=Query_p(t.p+1,t.r);
q.push(state(t.st,t.p+1,t.r,a[tp]-a[t.st-1],tp));
}
}
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}