RMQ练手题,只要不把题目读错就是道水题。
因为是连续的,不妨考虑前缀和。注意这里超级和弦不同值它们的位置不同(不是值)。
即求 m a x ( ∑ p r e [ r ] − p r e [ l − 1 ] ) max({\sum pre[r]-pre[l-1]}) max(∑pre[r]−pre[l−1])。把所有的数放进优先队列里显然是不行的。
套路,考虑将所有的左端点放进优先队列里面,则为一个五元组 ( i , l , r , v , n u m ) (i,l,r,v,num) (i,l,r,v,num), v v v 表示 m a x ( p r e [ l → r ] − p r e [ i − 1 ] ) max(pre[l\to r]-pre[i-1]) max(pre[l→r]−pre[i−1]), n u m num num 表示取到最大值的下标,想到了什么,RMQ!优先队列里就按 v v v 排序,取出五元组后,断成 ( i , l , n u m − 1 , v 1 , n u m 1 ) (i,l,num-1,v1, num1) (i,l,num−1,v1,num1) 和 ( i , n u m + 1 , r , v 2 , n u m 2 ) (i,num+1,r,v2,num2) (i,num+1,r,v2,num2)。想想就会发现这个正确性是可以保证的。因为每次只会增加一个元素,时间复杂度: O ( k l o g 2 ( n ) ) \mathcal{O}(klog_2(n)) O(klog2(n))。
Code
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <climits>
#include <queue>
#define Max(x, y) ((x)>(y)?(x):(y))
#define Min(x, y) ((x)<(y)?(x):(y))
using namespace std;
const int MAXN = 5e5 + 5;
struct Node {
int id, l, r, val, num;
bool operator < (const Node P) const { return val < P.val; }
Node() {}
Node(int x, int y, int z, int u, int v) { id = x; l = y; r = z; val = u; num = v; }
};
priority_queue <Node> que;
int n, k, l, r, a[MAXN], pre[MAXN], t, dp[20][MAXN], num[20][MAXN];
long long res;
void GET_RMQ() {
for(int i = 1; i <= t; i ++) {
for(int j = 1; j <= (n - (1 << i) + 1); j ++) {
dp[i][j] = Max(dp[i - 1][j], dp[i - 1][j + (1 << (i - 1))]);
num[i][j] = dp[i - 1][j] > dp[i - 1][j + (1 << (i - 1))] ? num[i - 1][j] : num[i - 1][j + (1 << (i - 1))];
}
}
}
int Query_val(int x, int y) { int p = log(y - x + 1) / log(2); return Max(dp[p][x], dp[p][y - (1 << p) + 1]); }
int Query_num(int x, int y) { int p = log(y - x + 1) / log(2); return dp[p][x] >= dp[p][y - (1 << p) + 1] ? num[p][x] : num[p][y - (1 << p) + 1]; }
int main() {
scanf("%d%d%d%d", &n, &k, &l, &r); t = log(n) / log(2) + 1;
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), pre[i] = pre[i - 1] + a[i], dp[0][i] = pre[i], num[0][i] = i;
GET_RMQ();
for(int i = 1; i <= n; i ++) {
if(i + l - 1 <= n) {
int L = i + l - 1, R = Min(i + r - 1, n);
que.push(Node(i, L, R, Query_val(L, R) - pre[i - 1], Query_num(L, R)));
}
}
for(int i = 1; i <= k; i ++) {
if(que.empty()) break;
Node t = que.top(); que.pop();
res += t.val;
if(t.l <= t.num - 1) que.push(Node(t.id, t.l, t.num - 1, Query_val(t.l, t.num - 1) - pre[t.id - 1], Query_num(t.l, t.num - 1)));
if(t.num + 1 <= t.r) que.push(Node(t.id, t.num + 1, t.r, Query_val(t.num + 1, t.r) - pre[t.id - 1], Query_num(t.num + 1, t.r)));
}
printf("%lld", res);
return 0;
}