码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-03-07 21:45:43      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:http   定义   优先队列   clu   zoj   efi   tput   stream   display   

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]超级钢琴 主席树+贪心+优先队列

标签:http   定义   优先队列   clu   zoj   efi   tput   stream   display   

原文地址:https://www.cnblogs.com/wls001/p/8524939.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!