• BZOJ 2006: [NOI2010]超级钢琴( RMQ + 堆 )


    取最大的K个, 用堆和RMQ来加速... 

    -----------------------------------------------------------------

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
     
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
     
    #define X(x) x.first
    #define Y(x) x.second
     
    const int maxn = 500009;
     
    struct node {
    int p, l, r, w, wp;
    node(int _p, int _l, int _r, int _w, int _wp) : p(_p), l(_l), r(_r), w(_w), wp(_wp) {
    }
    bool operator < (const node &o) const {
    return w < o.w;
    }
    };
     
    priority_queue<node> q;
    int N, K, L, R;
    int sum[maxn];
     
    struct ST {
    static const int maxlog = 22;
    pii Max[maxn][maxlog];
    void init() {
    for(int i = 1; i <= N; i++) { 
    X(Max[i][0]) = sum[i];
    Y(Max[i][0]) = i;
    }
    for(int i = 1; (1 << i) <= N; i++)
    for(int j = 1; j + (1 << i) - 1 <= N; j++)
    Max[j][i] = max(Max[j][i - 1], Max[j + (1 << (i - 1))][i - 1]);
    }
    pii query(int l, int r) {
    int t = 0;
    while((1 << t) <= r - l + 1) t++; t--;
    return max(Max[l][t], Max[r - (1 << t) + 1][t]);
    }
    } st;
     
    int main() {
    scanf("%d%d%d%d", &N, &K, &L, &R);
    sum[0] = 0;
    for(int i = 1; i <= N; i++) {
    scanf("%d", sum + i);
    sum[i] += sum[i - 1];
    }
    st.init();
    for(int i = 1; i + L - 1 <= N; i++) {
    int l = i + L - 1, r = min(N, i + R - 1);
    pii o = st.query(l, r);
    q.push(node(i, l, r, X(o) - sum[i - 1], Y(o)));
    }
    ll ans = 0;
    while(K--) {
    node o = q.top(); q.pop();
    ans += o.w;
    pii a = st.query(o.l, o.wp - 1), b = st.query(o.wp + 1, o.r);
    if(o.l < o.wp) q.push(node(o.p, o.l, o.wp - 1, X(a) - sum[o.p - 1], Y(a)));
    if(o.wp < o.r) q.push(node(o.p, o.wp + 1, o.r, X(b) - sum[o.p - 1], Y(b)));
    }
    printf("%lld ", ans);
    return 0;
    }

    ----------------------------------------------------------------- 

    2006: [NOI2010]超级钢琴

    Time Limit: 20 Sec  Memory Limit: 552 MB
    Submit: 1884  Solved: 920
    [Submit][Status][Discuss]

    Description

    小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。 这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。 一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。 小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最大值是多少。

    Input

    第一行包含四个正整数n, k, L, R。其中n为音符的个数,k为乐曲所包含的超级和弦个数,L和R分别是超级和弦所包含音符个数的下限和上限。 接下来n行,每行包含一个整数Ai,表示按编号从小到大每个音符的美妙度。

    Output

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

    Sample Input

    4 3 2 3

    3

    2

    -6

    8

    Sample Output

    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。

    HINT

    Source

  • 相关阅读:
    Oracle11g聚合函数
    和为S的连续正数数列,动态规划,C++
    统计一个数组在排序数组中出现的次数,C++,二分查找
    寻找两个链表的第一个公共子节点,C++
    二维数组中的查找
    数组中的逆序对,C++,分治算法
    得到从小到大的第N个丑数的三种方式(C++)一维动态规划
    连续字数组的最大和(Java)一个int数组,求其中的最大的连续数的和
    n个整数,求这中间最小的k个整数(Java)
    两个字符串的最长公共子串求法(C++、动态规划)
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4930756.html
Copyright © 2020-2023  润新知