• [BZOJ2006] [NOI2010]超级钢琴 主席树+贪心+优先队列


    2006: [NOI2010]超级钢琴

    Time Limit: 20 Sec  Memory Limit: 552 MB
    Submit: 3591  Solved: 1780
    [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,表示按编号从小到大每个音符的美妙度。
    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

    【样例说明】
    共有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

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<cstdio>
     7 #include<queue>
     8 #define maxn 500055
     9 #define ll long long
    10 using namespace std;
    11 int sum[maxn*30],ls[maxn*30],rs[maxn*30],rt[maxn],cnt;
    12 int n,K,L,R;
    13 int pre[maxn],h[maxn],num[maxn],size[maxn];
    14 struct data {
    15     int w,pos;
    16     bool operator <(const data tmp) const{return w<tmp.w;}
    17 };
    18 priority_queue<data> q;
    19 void insert(int &x,int p,int l,int r,int k) {
    20     x=++cnt;
    21     sum[x]=sum[p]+1,ls[x]=ls[p],rs[x]=rs[p];
    22     if(l==r) {return;}
    23     int mid=l+r>>1;
    24     if(k<=mid) insert(ls[x],ls[p],l,mid,k);
    25     else insert(rs[x],rs[p],mid+1,r,k);
    26 }
    27 int find(int x,int p,int l,int r,int k) {
    28 //    cout<<l<<' '<<r<<' '<<sum[ls[p]]<<' '<<sum[ls[x]]<<endl;
    29     if(l==r) return l;
    30     int mid=l+r>>1;
    31     if(sum[ls[p]]-sum[ls[x]]>=k) return find(ls[x],ls[p],l,mid,k);
    32     else return find(rs[x],rs[p],mid+1,r,k-(sum[ls[p]]-sum[ls[x]]));
    33 }
    34 int main() {
    35     scanf("%d%d%d%d",&n,&K,&L,&R);
    36     h[n+1]=0;
    37     for(int i=1;i<=n;i++) {
    38         int tmp;scanf("%d",&tmp);
    39         pre[i]=pre[i-1]+tmp;
    40         h[i]=pre[i];
    41     }
    42     sort(h+1,h+n+2);
    43     int nn=1;
    44     for(int i=2;i<=n+1;i++) if(h[i]!=h[nn]) h[++nn]=h[i];
    45     int hh=lower_bound(h+1,h+nn+1,0)-h;
    46     insert(rt[1],rt[1],1,n,hh);
    47     for(int i=1;i<=n;i++) {
    48         num[i]=lower_bound(h+1,h+nn+1,pre[i])-h;
    49         insert(rt[i+1],rt[i],1,n,num[i]);
    50     }
    51     for(int i=L;i<=n;i++) {
    52         if(i-L<0) continue;
    53         int w=find(rt[max(i-R,0)],rt[max(i-L+1,0)],1,n,size[i]+1);
    54         q.push((data){pre[i]-h[w],i});
    55     }
    56     ll ans=0;
    57     for(int i=1;i<=K;i++) {
    58         int w=q.top().w,pos=q.top().pos;
    59         ans+=(ll)w;
    60         size[pos]++;
    61         q.pop();
    62         int l=max(pos-R+1,1),r=pos-L+1;
    63         if(size[pos]>=r-l+1) continue;
    64         w=find(rt[l-1],rt[r],1,n,size[pos]+1);
    65         w=pre[pos]-h[w];
    66         q.push((data){w,pos});
    67     }
    68     printf("%lld
    ",ans);
    69 }
    View Code
  • 相关阅读:
    SQL通配符
    全角半角内容转换
    使用merge into 来更新目标表的个别字段
    数据库分库分表思路
    impdp导入错误ORA-14460
    CentOS只有GNOME桌面,没有GNOME经典桌面
    sqlserver进行发布订阅时提示实例上未安装复制组件解决方法
    SQLSERVER发布订阅,超详细
    sqlserver查询锁以及解锁
    sqlserver调用java文件
  • 原文地址:https://www.cnblogs.com/wls001/p/8524939.html
Copyright © 2020-2023  润新知