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

版权声明:欢迎转载蒟蒻博客,但请注明出处:blog.csdn.net/lpa20020220 https://blog.csdn.net/LPA20020220/article/details/82585975

洛谷传送门

BZOJ传送门

题目描述

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

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

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

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

输入输出格式

输入格式:

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

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

输出格式:

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

输入输出样例

输入样例#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

img

所有数据满足: 1000 A i 1000 1 L R n 且保证一定存在满足要求的乐曲。

扫描二维码关注公众号,回复: 3206280 查看本文章

解题分析

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

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

关于 R M Q 的部分用 s t 表即可。

总复杂度 O ( N l o g ( 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);
}

猜你喜欢

转载自blog.csdn.net/LPA20020220/article/details/82585975
今日推荐