题目
展开
题目描述
小 Z 是一个小有名气的钢琴家,最近 C 博士送给了小 Z 一架超级钢琴,小 Z 希望能够用这架钢琴创作出世界上最美妙的音乐。
这架超级钢琴可以弹奏出 nn 个音符,编号为 11 至 nn。第 ii 个音符的美妙度为 A_iA
i
,其中 A_iA
i
可正可负。
一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于 LL 且不多于 RR。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。
小 Z 决定创作一首由 kk 个超级和弦组成的乐曲,为了使得乐曲更加动听,小 Z 要求该乐曲由 kk 个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小 Z 想知道他能够创作出来的乐曲美妙度最大值是多少。
输入格式
输入第一行包含四个正整数 n, k, L, Rn,k,L,R。其中 nn 为音符的个数,kk 为乐曲所包含的超级和弦个数,LL 和 RR 分别是超级和弦所包含音符个数的下限和上限。
接下来 nn 行,每行包含一个整数 A_iA
i
,表示按编号从小到大每个音符的美妙度。
输出格式
输出只有一个整数,表示乐曲美妙度的最大值。
输入输出样例
输入 #1复制
4 3 2 3
3
2
-6
8
输出 #1复制
11
说明/提示
样例解释
共有 55 种不同的超级和弦:
音符 1 \sim 21∼2,美妙度为 3+2=53+2=5;
音符 2 \sim 32∼3,美妙度为 2+(-6)=-42+(−6)=−4;
音符 3 \sim 43∼4,美妙度为 (-6)+8=2(−6)+8=2;
音符 1 \sim 31∼3,美妙度为 3+2+(-6)=-13+2+(−6)=−1;
音符 2 \sim 42∼4,美妙度为 2+(-6)+8=42+(−6)+8=4。
最优方案为:乐曲由和弦 1,3,51,3,5 组成,美妙度为 5+2+4=115+2+4=11。
所有数据满足:-1000 \leq A_i \leq 1000−1000≤A
i
≤1000,1 \leq L \leq R \leq n1≤L≤R≤n 且保证一定存在满足要求的乐曲。
思路
这道题我们可以采取类似于贪心的思路,先找到最大值,然后删掉最大值,继续找剩下值中的最大值就可以了
假设现在我们一个区间都没删,现在要找最大值,
那么我们枚举左端点l,然后考虑对于一个给定的左端点l哪个是最优的右端点r 因为长度限制是[l,r]因此对于这个l来讲,所有合法的右端点r形成一个区间
当然是一个区间的前缀和值的最大值所对应的r了,因为总之你都要减去左端点的前缀和……,因此当然是要r的前缀和最大咯
这是一个区间最大值问题,当然可以使用st表解决这个问题
但是如果使用主席树解决这个静态区间第k大问题也不是不可以对吧……
然后我们对于每一个左端点都求出了一个最大合法的子串和
所以把这些值放进堆里取就可以找到最大值,好了我们现在有了一个最大值!
现在我们取出了这个最大值……我们发现此时这个左端点对应的区间第2大可能是此时最大的值,因此我们再求一遍区间第2大插堆里去,同理如果我们取出来来了区间第2大就插区间第3大,当然如果取掉了区间最小值就不能插入了……
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e5+77;
ll sum[N],table[N][20];
namespace RMQ {
void init(int n) {
for (int i = 1; i <= n; i++) table[i][0] = i;
for (int j = 1; (1 << j) <= n; j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
int x = table[i][j - 1],y = table[i + (1 << (j - 1))][j - 1];
table[i][j] = sum[x] > sum[y] ? x : y;
}
}
int query(int l,int r) {
int k = log2(r - l + 1);
int x = table[l][k],y = table[r - (1 << k) + 1][k];
return sum[x] > sum[y] ? x : y;
}
}
struct element {
int o,l,r,t;
element() {}
element(int o,int l,int r) : o(o),l(l),r(r),t(RMQ::query(l,r)) {}
friend bool operator < (const element& a,const element& b) {
return sum[a.t] - sum[a.o - 1] < sum[b.t] - sum[b.o - 1];
}
};
std::priority_queue< element > Q;
int main() {
int n,k,L,R;
scanf("%d%d%d%d",&n,&k,&L,&R);
for (int i = 1; i <= n; i++) {
scanf("%lld",&sum[i]);
sum[i] += sum[i - 1];
}
RMQ::init(n);
for (int i = 1; i <= n; i++)
if (i + L - 1 <= n)
Q.push(element(i,i + L - 1,min(i + R - 1,n)));
ll ans = 0;
while (k--) {
int o = Q.top().o,l = Q.top().l,r = Q.top().r,t = Q.top().t;
Q.pop();
ans += sum[t] - sum[o - 1];
if (l != t) Q.push(element(o,l,t - 1));
if (t != r) Q.push(element(o,t + 1,r));
}
printf("%lld\n",ans);
return 0;
}
本文介绍了一种算法,用于帮助钢琴家小Z利用超级钢琴创作美妙的乐曲。通过寻找最佳的超级和弦组合,算法实现了乐曲美妙度的最大化。讨论了如何采用类似贪心的策略,结合st表和主席树解决静态区间第k大问题。
630

被折叠的 条评论
为什么被折叠?



