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

Posted wls001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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\n",ans);
69 }
View Code

 

















以上是关于[BZOJ2006] [NOI2010]超级钢琴 主席树+贪心+优先队列的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2006: [NOI2010]超级钢琴

[BZOJ2006][NOI2010]超级钢琴

bzoj 2006 [NOI2010]超级钢琴 rmq+堆

BZOJ2006[NOI2010]超级钢琴 ST表+堆

[BZOJ2006][NOI2010]超级钢琴(ST表+堆)

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