#include <bits/stdc++.h>
//using int_max = 0x3f3f3f3f;
#define long_max 9223372036854775807;
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
using VI = vector<int>;
typedef unsigned long long ull;
const int mod = 1e8 - 3;
int n,k,l,r;
int a[5000010];
int s[5000010];
int st[5000010][32];
int id[5000010][32];
struct range{
int pos,l,r,mp;
bool operator < (range u)const{
return s[mp] - s[pos-1] < s[u.mp] - s[u.pos-1];
}
}tmp;
void init(){
for(int i=1;i<=n;i++){
st[i][0] = s[i];
id[i][0] = i;
}
for(int j=1;j<=log2(n)+1;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
if(st[i][j-1] > st[i+(1<<(j-1))][j-1]){
st[i][j] = st[i][j-1];
id[i][j] = id[i][j-1];
}else{
st[i][j] = st[i+(1<<(j-1))][j-1];
id[i][j] = id[i+(1<<(j-1))][j-1];
}
}
}
}
int query(int l, int r){
int k = log2(r-l+1);
if(st[l][k] > st[r-(1<<k)+1][k]){
return id[l][k];
}else{
return id[r-(1<<k)+1][k];
}
}
int main() {
cin>>n>>k>>l>>r;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) s[i] = s[i-1] + a[i];
init();
priority_queue<range> q;
for(int i=1;i+l-1<=n;i++){
tmp.pos = i;
tmp.l = i+l-1;
tmp.r = min(n,i+r-1);
tmp.mp = query(tmp.l,tmp.r);
//cout<<tmp.pos<<" "<<tmp.mp<<"\n";
q.push(tmp);
}
ll res = 0;
while(k--){
auto u = q.top();
q.pop();
int pos = u.pos;
int l = u.l;
int r = u.r;
int mp = u.mp;
//cout<<pos<<" "<<mp<<"\n";
res += s[mp] - s[pos-1];
if(mp > l){
tmp.pos = pos;
tmp.l = l;
tmp.r = mp-1;
tmp.mp = query(tmp.l,tmp.r);
q.push(tmp);
}
if(mp < r){
tmp.pos = pos;
tmp.l = mp+1;
tmp.r = r;
tmp.mp = query(tmp.l,tmp.r);
q.push(tmp);
}
}
cout<<res;
}
洛谷首个紫,
其实思路并不难,主要是代码实现方面脑子灵光不够
本质上来说就是RMQ问题
当前端点为 i 选择 i+l-1 i+r-1 中的最大值,位置为k,
然后就考虑选取次大值,其中次大值一定再 i+l-1 , k -1 或者 k + 1 , i+r-1 中
简单点说,就是选择一个最大值,从最大值的位置把区间分开,构成俩个新的待选区间