【BZOJ2006】【NOI2010】超级钢琴(堆)

21 篇文章 0 订阅
3 篇文章 0 订阅

Description

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

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

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

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

Solution

设一个四元组(i,l,r,t)表示当前以i为左端点,[l,r]一定为可行的区间的子集,t表示[l,r]最大前缀和的下标。维护一个堆,对于堆顶元素,贡献完答案后,插入 (i,l,t1,query(l,t1)) ( i , l , t − 1 , q u e r y ( l , t − 1 ) ) (i,t+1,r,query(t+1,r)) ( i , t + 1 , r , q u e r y ( t + 1 , r ) ) 。可以用st表来维护。

Source

啥?用了make_heap卡常还比肖大佬跑得慢,果然自带大常数。。。

/************************************************
 * Au: Hany01
 * Date: Mar 2nd, 2018
 * Prob: [BZOJ2006][NOI2010] 超级钢琴
 * Email: hany01@foxmail.com
************************************************/

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define fir first
#define sec second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define Mod (1000000007)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia

template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }

inline int read()
{
    register int _, __; register char c_;
    for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
    for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
    return _ * __;
}

inline void File()
{
#ifdef hany01
    freopen("bzoj2006.in", "r", stdin);
    freopen("bzoj2006.out", "w", stdout);
#endif
}

const int maxn = 500005, maxlog = 20;

int n, k, L, R, Log2[maxn], f[maxn][maxlog], Sum[maxn];

struct Item
{
    int st, l, r, ed;

    Item(int st = 0, int l = 0, int r = 0, int ed = 0): st(st), l(l), r(r), ed(ed) {}

    bool operator < (const Item& item) const {
        return Sum[ed] - Sum[st - 1] < Sum[item.ed] - Sum[item.st - 1];
    }
};

inline void Init()
{
    n = read(), k = read(), L = read(), R = read(), Log2[0] = -1;
    For(i, 1, n) Sum[i] = Sum[i - 1] + read(), Log2[i] = Log2[i >> 1] + 1, f[i][0] = i;
    For(i, 1, Log2[n]) For(j, 1, n - (1 << i) + 1)
        if (Sum[f[j][i - 1]] > Sum[f[j + (1 << (i - 1))][i - 1]]) f[j][i] = f[j][i - 1]; else f[j][i] = f[j + (1 << (i - 1))][i - 1];
}

inline int query(int l, int r) {
    int tmp = Log2[r - l + 1];
    if (Sum[f[l][tmp]] > Sum[f[r - (1 << tmp) + 1][tmp]]) return f[l][tmp]; else return f[r - (1 << tmp) + 1][tmp];
}

inline void Solve()
{
    static Item q[maxn * 3], top;
    static int l, r, cnt = 0;
    static LL Ans = 0;

    For(i, 1, n) {
        l = i + L - 1, r = min(i + R - 1, n);
        if (l <= r) q[cnt ++] = Item(i, l, r, query(l, r));
    }
    make_heap(q, q + cnt);

    while (k --) {
        top = q[0], Ans += Sum[top.ed] - Sum[top.st - 1], pop_heap(q, q + cnt --);
        l = top.l, r = top.ed - 1;
        if (l <= r) q[cnt ++] = Item(top.st, l, r, query(l, r)), push_heap(q, q + cnt);
        l = top.ed + 1, r = top.r;
        if (l <= r) q[cnt ++] = Item(top.st, l, r, query(l, r)), push_heap(q, q + cnt);
    }

    printf("%lld\n", Ans);
}

int main()
{
    File();

    Init();

    Solve();

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值