洛谷 P2048 BZOJ 2006 [NOI2010]超級鋼琴
題目描述
小Z是一個小有名氣的鋼琴家,最近C博士送給了小Z一架超級鋼琴,小Z希望能夠用這架鋼琴創作出世界上最美妙的音樂。
這架超級鋼琴可以彈奏出n個音符,編號為1至n。第i個音符的美妙度為Ai,其中Ai可正可負。
一個“超級和弦”由若幹個編號連續的音符組成,包含的音符個數不少於L且不多於R。我們定義超級和弦的美妙度為其包含的所有音符的美妙度之和。兩個超級和弦被認為是相同的,當且僅當這兩個超級和弦所包含的音符集合是相同的。
小Z決定創作一首由k個超級和弦組成的樂曲,為了使得樂曲更加動聽,小Z要求該樂曲由k個不同的超級和弦組成。我們定義一首樂曲的美妙度為其所包含的所有超級和弦的美妙度之和。小Z想知道他能夠創作出來的樂曲美妙度最大值是多少。
輸入輸出格式
輸入格式:
輸入第一行包含四個正整數n, k, L, R。其中n為音符的個數,k為樂曲所包含的超級和弦個數,L和R分別是超級和弦所包含音符個數的下限和上限。
接下來n行,每行包含一個整數Ai,表示按編號從小到大每個音符的美妙度。
輸出格式:
輸出只有一個整數,表示樂曲美妙度的最大值。
輸入輸出樣例
輸入樣例#1:
4 3 2 3
3
2
-6
8
輸出樣例#1:
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。
題解
堆+st表
我們定義一個三元組\((s, l, r)\) 表示以s為左端點 右端點在\(l-r\)這段區間內區間和最大
維護一個前綴和
貪心地想,既然\(s\)已經固定那麽對於右端點在\(l-r\)這段區間內,我們要取前綴和最大的那個值,st搞一下就好了
定義\(t\)為\(l-r\)區間前綴和最大的位置
我們維護一個堆
每次取出價值最大
然後把\((s, l, t-1) (s, t+1, r)\)放進去
註意特判一下\(l=t, r=t\)
Code
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
inline int gi() {
int f = 1, s = 0;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -1, c = getchar();
while (c >= '0' && c <= '9') s = s*10+c-'0', c = getchar();
return f == 1 ? s : -s;
}
const int N = 500010;
int mx[N][21], a[N], n, k, L, R;
LL sum[N];
void init() {
for (int i = 1; i <= n; i++)
mx[i][0] = i;
for (int i = 1; (1<<i) <= n; i++)
for (int j = 1; j + (1<<i) - 1 <= n; j++) {
int x = mx[j][i-1], y = mx[j+(1<<(i-1))][i-1];
mx[j][i] = sum[x] > sum[y] ? x : y;
}
return ;
}
inline int getmax(int l, int r) {
int k = log2(r-l+1), x = mx[l][k], y = mx[r-(1<<k)+1][k];
return sum[x] > sum[y] ? x : y;
}
struct node {
int s, l, r, t;
bool operator <(node z) const {
return (sum[t]-sum[s-1]) < (sum[z.t]-sum[z.s-1]);
}
};
priority_queue<node> q;
int main() {
n = gi(), k = gi(), L = gi(), R = gi();
for (int i = 1; i <= n; i++) {
a[i] = gi();
sum[i] = sum[i-1]+a[i];
}
init();
for (int i = 1; i+L-1 <= n; i++)
q.push((node) {i, i+L-1, min(n, i+R-1), getmax(i+L-1, min(n, i+R-1))});
LL ans = 0;
for (int i = 1; i <= k; i++) {
int l = q.top().l, r = q.top().r, s = q.top().s, t = q.top().t;
q.pop();
ans += sum[t]-sum[s-1];
if (t != l)
q.push((node) {s, l, t-1, getmax(l, t-1)});
if (t != r)
q.push((node) {s, t+1, r, getmax(t+1, r)});
}
printf("%lld\n", ans);
return 0;
}
洛谷 P2048 BZOJ 2006 [NOI2010]超級鋼琴