Description
小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。 这架超级钢琴可以弹奏出 n 个音符,编号为 1 至 n。第i个音符的美妙度为 Ai,其中 Ai 可正可负。 一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于 L 且不多于 R。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。 小Z决定创作一首由 k 个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由 k 个不同的超级和弦组成。
我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最
大值是多少。
Input
第一行包含四个正整数 n, k, L, R。其中 n 为音符的个数,k 为乐曲所包含的超级和弦个数,L和R分别是超级和弦所包含音符个数的下限和上限。 接下来 n 行,每行包含一个整数 Ai ,表示按编号从小到大每个音符的美妙度。
Output
只有一个整数,表示乐曲美妙度的最大值。
Sample Input
4 3 2 3
3
2
-6
8
Sample Output
11
[样例说明]
共有5种不同的超级和弦:
音符1 ~ 2,美妙度为3 + 2 = 5
音符2 ~ 3,美妙度为2 + (-6) = -4
音符3 ~ 4,美妙度为(-6) + 8 = 2
音符1 ~ 3,美妙度为3 + 2 + (-6) = -1
音符2 ~ 4,美妙度为2 + (-6) + 8 = 4
最优方案为:乐曲由和弦1,和弦3,和弦5组成,美妙度为5 + 2 + 4 = 11。
HINT
N <= 500,000,k <= 500,000
-1000 <= Ai <= 1000, 1 <= L <= R<= N且保证一定存在满足条件的乐曲
Solution :
这道题需要找到子区间第
K
大的值,那我们先考虑如何给定一个端点去找最大的区间,首先算区间和很容易前缀,然后是给定区间大小寻找区间,因为一个端点是定的,这里我定的是左端点, 我们只需要去寻找右区间的前缀的最大值,从公式是很容易看出
现在考虑找到第
K
大的用法,我们可以用个堆维护信息,每次维护
Code :
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <ctime>
#include <map>
#include <vector>
#include <queue>
#define LL long long
using namespace std;
inline int read() {
int i = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = -1; ch = getchar();
}
while(isdigit(ch)) {
i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();
}
return i * f;
}
const int MAXN = 5e5 + 5;
int a[MAXN], pre[MAXN], n, k, Log[MAXN], mx[20][MAXN];
LL ans;
struct point {
int l, r, i, val, pos;
point() {}
point(int _l, int _r, int _i, int _val, int _pos) : l(_l), r(_r), i(_i), val(_val), pos(_pos) {}
bool operator < (const point & a) const {
return val < a.val;
}
};
inline int new_max(int x, int y) {
return pre[x] > pre[y] ? x : y;
}
inline void ST() {
Log[0] = -1;
for(int i = 1; i <= n; ++i) Log[i] = Log[i >> 1] + 1;
for(int i = 1; i <= n; ++i) mx[0][i] = i;
for(int j = 1; (1 << j) <= n; ++j)
for(int i = 1; i + (1 << j) - 1 <= n; ++i)
mx[j][i] = new_max(mx[j - 1][i], mx[j - 1][i + (1 << j - 1)]);
}
inline int find(int l, int r) {
int k = Log[r - l + 1];
return new_max(mx[k][l], mx[k][r - (1 << k) + 1]);
}
priority_queue<point> q;
inline void wr(LL x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) wr(x / 10);
putchar(x % 10 + '0');
}
int main() {
n = read(), k = read(); int L = read(), R = read();
for(int i = 1; i <= n; ++i) a[i] = read(), pre[i] = pre[i - 1] + a[i];
ST();
for(int i = 1; i <= n; ++i)
if(i + L - 1 <= n) {
int ls = i + L - 1, rs = min(i + R - 1, n);
int pos = find(ls, rs), val = pre[pos] - pre[i - 1];
q.push(point(ls, rs, i, val, pos));
}
else break;
while(!q.empty() && k) {
--k;
point now = q.top(); q.pop();
ans += now.val;
point ls = now, rs = now;
ls.r = now.pos - 1;
if(ls.r >= ls.l)
ls.pos = find(ls.l, ls.r), ls.val = pre[ls.pos] - pre[ls.i - 1], q.push(ls);
rs.l = now.pos + 1;
if(rs.r >= rs.l)
rs.pos = find(rs.l, rs.r), rs.val = pre[rs.pos] - pre[rs.i - 1], q.push(rs);
}
wr(ans);
}