• BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表


    BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表

    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,表示按编号从小到大每个音符的美妙度。
    N<=500,000
    k<=500,000
    -1000<=Ai<=1000,1<=L<=R<=N且保证一定存在满足条件的乐曲

    Output

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

    Sample Input

    4 3 2 3
    3
    2
    -6
    8

    Sample Output

    11


    把所有的子串当成后缀的前缀来做。

    那么对于从i这个位置开始的子串,有一个可以选取末位置j的范围[i+L-1,i+R-1]。

    假设最大的合法子串在j这个位置,那么次大值一定出现在[i+L-1,j-1]和[j+1,i+R-1]中。

    于是有了这样的想法:用堆来维护四元组<i,p,l,r>表示从i到p的子段,选择的范围从l到r。

    然后每次查询区间最大值用ST表做即可。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <ext/pb_ds/priority_queue.hpp>
    using namespace std;
    using namespace __gnu_pbds;
    typedef long long ll;
    #define N 500050
    int n,a[N],s[N],K,L,R,f[N][21],Lg[N],g[N][21];
    ll ans;
    struct A {
        int x,p,l,r;
        A() {}
        A(int x_,int p_,int l_,int r_) :
            x(x_),p(p_),l(l_),r(r_) {}
    };
    bool operator < (const A &x,const A &y) {
        return s[x.p]-s[x.x-1]<s[y.p]-s[y.x-1];
    }
    __gnu_pbds::priority_queue<A>q;
    int get_max(int l,int r) {
        int len=Lg[r-l+1];
        return f[l][len]>f[r-(1<<len)+1][len]?g[l][len]:g[r-(1<<len)+1][len];
    }
    void solve() {
        int i;
        for(i=1;i<=n-L+1;i++) {
            int t=get_max(i+L-1,min(n,i+R-1));
            q.push(A(i,t,i+L-1,min(n,i+R-1)));
        }
        for(i=1;i<=K;i++) {
            A t=q.top(); q.pop();
            //printf("%d %d
    ",t.x,t.p);
            ans+=s[t.p]-s[t.x-1];
            if(t.p>t.l) q.push(A(t.x,get_max(t.l,t.p-1),t.l,t.p-1));
            if(t.p<t.r) q.push(A(t.x,get_max(t.p+1,t.r),t.p+1,t.r));
        }
    }
    int main() {
        scanf("%d%d%d%d",&n,&K,&L,&R);
        int i,j;
        Lg[0]=-1;
        for(i=1;i<=n;i++) {
            scanf("%d",&a[i]);
            s[i]=s[i-1]+a[i];
            f[i][0]=s[i];
            g[i][0]=i;
            Lg[i]=Lg[i>>1]+1;
        }
        Lg[0]=0;
        for(j=1;(1<<j)<=n;j++) {
            for(i=1;i+(1<<j)-1<=n;i++) {
                if(f[i][j-1]>f[i+(1<<j-1)][j-1]) {
                    f[i][j]=f[i][j-1];
                    g[i][j]=g[i][j-1];
                }else {
                    f[i][j]=f[i+(1<<j-1)][j-1];
                    g[i][j]=g[i+(1<<j-1)][j-1];
                }
            }
        }
        solve();
        printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    Tomcat下HTTPS双向认证配置以及客户端调用案例
    Java本地运行中文正常,部署到Weblogic中文乱码
    gson 忽略掉某些字段不进行转换
    JavaScript中定义对象的四种方式
    使用CSS3实现超炫的Loading(加载)动画效果
    不要再使用JS框架了
    HTML5, CSS3, ES5新的web标准和浏览器支持一览 转
    js常用的事件对象
    jQuery用面向对象的思想来编写验证表单的插件
    五个值得尝试的前端开发工具
  • 原文地址:https://www.cnblogs.com/suika/p/9022822.html
Copyright © 2020-2023  润新知