题意
题解
将区间和转化为前缀和 s u m sum sum 之差,那么问题转化为求满足条件的点对 ( i , j ) , i < j (i,j),i<j (i,j),i<j 中 s u m [ j ] − s u m [ i ] sum[j]-sum[i] sum[j]−sum[i] 的最大值。对于每个点 i i i,以其为左界可取得的最大区间和为 max i + L − 1 i + R − 1 s u m [ j ] − s u m [ i − 1 ] \text{max}_{i+L-1}^{i+R-1}sum[j]-sum[i-1] maxi+L−1i+R−1sum[j]−sum[i−1] 由于 i i i 固定,只关注第一项可取得的最大值。设第一项取得最大值的位置为 p p p,那么以 i i i 为左界可取得的区间次大值对应的 p ′ p' p′ 为取得下式的对应位置 max ( max i + L − 1 p − 1 s u m [ j ] , max p + 1 i + R − 1 s u m [ j ] ) \text{max}\big(\text{max}_{i+L-1}^{p-1}sum[j],\text{max}_{p+1}^{i+R-1}sum[j]\big) max(maxi+L−1p−1sum[j],maxp+1i+R−1sum[j]) 区间个数为 N 2 N^2 N2,为了减少搜索的区间数,枚举左界,仅拓展其最大区间和,并用大根堆维护;不断取出堆顶,将对应的区间次大和的可能位置插入二叉堆。
使用 S T ST ST 算法实现 R M Q RMQ RMQ,总时间复杂度为 O ( ( N + K ) log N ) O((N+K)\log N) O((N+K)logN)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 500005, maxlg = 20;
int N, K, L, R, A[maxn], sum[maxn];
int lg[maxn], mx[maxn][maxlg], pos[maxn][maxlg];
struct node
{
int d, i, p, l, r;
bool operator<(const node &b) const { return d < b.d; }
};
priority_queue<node> Q;
inline int read()
{
int x = 0, f = 0;
char c = 0;
for (; c < '0' || c > '9'; c = getchar())
if (c == '-')
f = 1;
for (; c >= '0' && c <= '9'; c = getchar())
x = (x << 1) + (x << 3) + c - '0';
return f ? -x : x;
}
void st_init()
{
lg[0] = -1;
for (int i = 1; i <= N; ++i)
lg[i] = lg[i - 1] + (1 << (lg[i - 1] + 1) == i);
for (int i = 1; i <= N; ++i)
mx[i][0] = sum[i], pos[i][0] = i;
for (int k = 1; k <= lg[N]; ++k)
for (int i = 1, j; i + (1 << k) - 1 <= N; ++i)
{
j = i + (1 << (k - 1));
mx[i][k] = max(mx[i][k - 1], mx[j][k - 1]);
pos[i][k] = mx[i][k - 1] > mx[j][k - 1] ? pos[i][k - 1] : pos[j][k - 1];
}
}
inline int ask(int l, int r)
{
int k = lg[r - l + 1], m = r - (1 << k) + 1;
return mx[l][k] > mx[m][k] ? pos[l][k] : pos[m][k];
}
inline int get(int l, int r) { return sum[r] - sum[l - 1]; }
int main()
{
N = read(), K = read(), L = read(), R = read();
for (int i = 1; i <= N; ++i)
A[i] = read(), sum[i] = A[i] + sum[i - 1];
st_init();
for (int i = 1, p, l, r; i <= N; ++i)
{
l = i + L - 1, r = i + R - 1;
if (l > N)
continue;
r = min(r, N), p = ask(l, r);
Q.push(node{get(i, p), i, p, l, r});
}
ll res = 0;
for (int i = 1, p; i <= K; ++i)
{
node t = Q.top();
Q.pop();
res += t.d;
if (t.p > t.l)
p = ask(t.l, t.p - 1), Q.push(node{get(t.i, p), t.i, p, t.l, t.p - 1});
if (t.p < t.r)
p = ask(t.p + 1, t.r), Q.push(node{get(t.i, p), t.i, p, t.p + 1, t.r});
}
printf("%lld\n", res);
return 0;
}