P2048 [NOI2010] 超级钢琴 题解
\(Description\)
\(Solution\)
早就想做这道 P2048 了,但是之前太菜了,不会 QwQ
RMQ + 前缀和 + 堆
显然要做一个前缀和,但是做完前缀和之后暴力枚举区间显然是不行的。
考虑一下我们到底要计算什么:
对于一个点 \(u\),我们要计算 \(\max\{sum_t - sum_{u - 1}\}\ (\ t \in [u + L - 1, u + R - 1])\)
\(sum_{u - 1}\) 是固定的,所以我们要使用某种方法快速计算出 \(\max\{sum_t\}\ \ (t \in [u + L - 1, u + R - 1])\)
这时候 \(RMQ\) 就闪亮登场了。
关于 \(RMQ\) 不会的话去看其他 dalao 的博客吧=-=
简单来说就是开个数组 \(f_{i, k}\) 表示从 \(i\) 开始长度为 \(2^k\) 的区间中的(最大值/最小值)。
然后预处理一下这个数组,查询的时候就可以 \(O(1)\) 查询了。
然后类似于 异或粽子 那题,开个大根堆,每次取出当前堆顶,插入次大的值。
重复上述操作即可。
\(Code\)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
namespace IO{
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
template <typename T> inline void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;
const int N = 5e5 + 10;
int n, k, L, R;
int f[N][20];
ll sum[N];
inline void init(){
for(int i = 1; i <= n; ++i) f[i][0] = i;
for(int j = 1; (1 << j) <= n; ++j)
for(int i = 1; i + (1 << j) - 1 <= n; ++i){
int x = f[i][j - 1], y = f[i + (1 << (j - 1))][j - 1];
f[i][j] = sum[x] > sum[y] ? x : y;
}
}
inline int query(int l, int r){
int k = log2(r - l + 1);
int x = f[l][k], y = f[r - (1 << k) + 1][k];
return sum[x] > sum[y] ? x : y;
}
struct node{
int u, l, r, t;
node(int _u = 0, int _l = 0, int _r = 0){
u = _u, l = _l, r = _r, t = query(_l, _r);
}
inline bool operator < (const node &b) const{
return sum[t] - sum[u - 1] < sum[b.t] - sum[b.u - 1];
}
};
priority_queue <node> q;
int main(){
n = read(), k = read(), L = read(), R = read();
for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + read();
init();
for(int i = 1; i <= n; ++i)
if(i + L - 1 <= n) q.push(node{i, i + L - 1, min(i + R - 1, n)});
ll ans = 0;
while(k--){
node now = q.top(); q.pop();
ans += sum[now.t] - sum[now.u - 1];
if(now.t != now.l) q.push(node{now.u, now.l, now.t - 1});
if(now.t != now.r) q.push(node{now.u, now.t + 1, now.r});
}
write(ans), puts("");
return 0;
}
\[\_EOF\_
\]