欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Luogu P2048] [BZOJ 2006] [NOI2010]超级钢琴

程序员文章站 2022-07-13 11:58:21
...

洛谷传送门

BZOJ传送门

题目描述

小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。

这架超级钢琴可以弹奏出n个音符,编号为1n。第i个音符的美妙度为Ai,其中Ai可正可负。

一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。

小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最大值是多少。

输入输出格式

输入格式:

输入第一行包含四个正整数n,k,L,R。其中n为音符的个数,k为乐曲所包含的超级和弦个数,LR分别是超级和弦所包含音符个数的下限和上限。

接下来n行,每行包含一个整数Ai,表示按编号从小到大每个音符的美妙度。

输出格式:

输出只有一个整数,表示乐曲美妙度的最大值。

输入输出样例

输入样例#1:

4 3 2 3
3
2
-6
8

输出样例#1:

11

说明

共有5种不同的超级和弦:

1.    音符1 ~ 2,美妙度为3 + 2 = 5
2.    音符2 ~ 3,美妙度为2 + (-6) = -4
3.    音符3 ~ 4,美妙度为(-6) + 8 = 2
4.    音符1 ~ 3,美妙度为3 + 2 + (-6) = -1
5.    音符2 ~ 4,美妙度为2 + (-6) + 8 = 4

最优方案为:乐曲由和弦1,和弦3,和弦5组成,美妙度为5+2+4=11

[Luogu P2048] [BZOJ 2006] [NOI2010]超级钢琴

所有数据满足:1000Ai10001LRn且保证一定存在满足要求的乐曲。

解题分析

最暴力的做法就是提出N2个区间然后排序找出前k小了, 然而会T成狗…

既然我们不能保存所有的区间, 我们就先提出一些最优的。 可以发现以某个点为左端点的区间的最优值共有O(N)个, 那么我们对于每个左端点保存一个最优值, 以及当前的位置、 合法的区间。 每次取出堆顶更新答案, 然后划分左右的合法区间重新加入堆中。

关于RMQ的部分用st表即可。

总复杂度O(Nlog(N))

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <queue>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 500050
#define ll long long
bool neg;
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc)
    if(c == '-') neg = true;
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
    if(neg) neg = false, x = -x;
}
int dot, l, r, k, bd;
ll pre[MX], st[20][MX], ans;
struct INFO {ll val; int st, lef, rig, pos;};
IN bool operator < (const INFO &x, const INFO &y) {return x.val < y.val;}
std::priority_queue <INFO> pq;
IN void init()
{
    bd = log2(dot); int step, ed;
    for (R int i = 1; i <= dot; ++i) st[0][i] = i;
    for (R int t = 1; t <= bd; ++t)
    {
        step = 1 << t - 1; ed = dot - (step << 1) + 1;
        for (R int i = 1; i <= ed; ++i)
        st[t][i] = pre[st[t - 1][i]] > pre[st[t - 1][i + step]] ? st[t - 1][i] : st[t - 1][i + step];
    }
}
IN int query(R int lef, R int rig)
{
    int seg = log2(rig - lef + 1);
    return pre[st[seg][lef]] > pre[st[seg][rig - (1 << seg) + 1]] ? st[seg][lef] : st[seg][rig - (1 << seg) + 1];
}
int main(void)
{
    int st, ed, tar;
    INFO cur;
    in(dot), in(k), in(l), in(r);
    for (R int i = 1; i <= dot; ++i) in(pre[i]), pre[i] += pre[i - 1];
    init();
    for (R int i = 1; i <= dot; ++i)
    {
        st = i + l - 1, ed = i + r - 1;
        ed = std::min(ed, dot);
        if(st > ed) break;
        tar = query(st, ed);
        pq.push({pre[tar] - pre[i - 1], i, st, ed, tar});
    }
    W(k--)
    {
        cur = pq.top(); pq.pop();
        ans += cur.val;
        st = cur.pos - 1, ed = cur.pos + 1;
        if(st >= cur.lef)
        {
            tar = query(cur.lef, st);
            pq.push({pre[tar] - pre[cur.st - 1], cur.st, cur.lef, st, tar});
        }
        if(ed <= cur.rig)
        {
            tar = query(ed, cur.rig);
            pq.push({pre[tar] - pre[cur.st - 1], cur.st, ed, cur.rig, tar});
        }
    }
    printf("%lld", ans);
}
相关标签: st表