[NOI2010]超级钢琴
Posted Mafia
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOI2010]超级钢琴相关的知识,希望对你有一定的参考价值。
[NOI2010]超级钢琴
题目
小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。
这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。
一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。
小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最大值是多少。
INPUT
输入文件名为piano.in。
输入文件第一行包含四个正整数n, k, L, R。其中n为音符的个数,k为乐曲所包含的超级和弦个数,L和R分别是超级和弦所包含音符个数的下限和上限。
接下来n行,每行包含一个整数Ai,表示按编号从小到大每个音符的美妙度。
OUTPUT
输出文件为piano.out。
输出文件只有一个整数,表示乐曲美妙度的最大值。
SAMPLE
INPUT
4 3 2 3
3
2
-6
8
OUTPUT
11
解题报告
强制转换果然不能乱用= =
枚举左端点,用$ST$表找到满足条件的前缀和最大区间右端点,扔进堆里,每次取堆顶,分裂区间,再扔进堆里
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<queue> 6 using namespace std; 7 typedef long long LL; 8 inline LL read(){ 9 LL sum(0),f(1); 10 char ch(getchar()); 11 for(;ch<\'0\'||ch>\'9\';ch=getchar()) 12 if(ch==\'-\') 13 f=-1; 14 for(;ch>=\'0\'&&ch<=\'9\';sum=sum*10+(ch^48),ch=getchar()); 15 return sum*f; 16 } 17 LL ans; 18 struct node{ 19 int l,r; 20 LL v; 21 int L,R; 22 inline bool operator<(const node &x)const{ 23 return v<x.v; 24 } 25 }; 26 priority_queue<node>q; 27 int n,k,ll,rr; 28 LL sum[500005],mx[500005][22]; 29 int pos[500005][22]; 30 inline void ST(){ 31 for(int i=1;(1<<i)<=n;++i) 32 for(int j=1;j+(1<<i)-1<=n;++j){ 33 if(mx[j][i-1]>mx[j+(1<<i-1)][i-1]){ 34 mx[j][i]=mx[j][i-1]; 35 pos[j][i]=pos[j][i-1]; 36 } 37 else{ 38 mx[j][i]=mx[j+(1<<i-1)][i-1]; 39 pos[j][i]=pos[j+(1<<i-1)][i-1]; 40 } 41 // cout<<i<<\' \'<<j<<\' \'<<mx[j][i]<<\' \'<<pos[j][i]<<endl; 42 } 43 } 44 inline int query(int l,int r){ 45 if(l>r) 46 return 0; 47 int k(0),len(r-l+1); 48 while((1<<k)<=len)++k; 49 --k; 50 if(mx[l][k]>mx[r-(1<<k)+1][k]) 51 return pos[l][k]; 52 else 53 return pos[r-(1<<k)+1][k]; 54 } 55 int main(){ 56 // freopen("piano.in","r",stdin); 57 // freopen("piano.out","w",stdout); 58 n=read(),k=read(),ll=read(),rr=read(); 59 for(int i=1;i<=n;++i){ 60 sum[i]=sum[i-1]+read(); 61 mx[i][0]=sum[i]; 62 pos[i][0]=i; 63 // cout<<i<<" "<<sum[i]<<\' \'<<mx[i][0]<<" "<<pos[i][0]<<endl; 64 } 65 ST(); 66 for(int i=1;i<=n-ll+1;++i){ 67 int tp1(i+ll-1),tp2(min(i+rr-1,n)); 68 int tmp(query(tp1,tp2)); 69 // cout<<i<<\' \'<<tmp<<\' \'<<sum[tmp]-sum[i-1]<<\' \'<<tp1<<\' \'<<tp2<<endl; 70 q.push((node){i,tmp,sum[tmp]-sum[i-1],tp1,tp2}); 71 } 72 int cnt(0); 73 while(cnt<k){ 74 ++cnt; 75 node tmp(q.top()); 76 q.pop(); 77 ans+=tmp.v; 78 // cout<<cnt<<" "<<ans<<endl; 79 // cout<<tmp.l<<" "<<tmp.r<<" "<<tmp.v<<" "<<tmp.L<<\' \'<<tmp.R<<endl; 80 int tp1(query(tmp.L,tmp.r-1)),tp2(query(tmp.r+1,tmp.R)); 81 if(tmp.r-1>=tmp.L){ 82 q.push((node){tmp.l,tp1,sum[tp1]-sum[tmp.l-1],tmp.L,tmp.r-1}); 83 // cout<<"first"<<tmp.l<<\' \'<<tp1<<\' \'<<sum[tp1]-sum[tmp.l-1]<<\' \'<<tmp.L<<\' \'<<tmp.r-1<<endl; 84 } 85 if(tmp.r+1<=tmp.R){ 86 q.push((node){tmp.l,tp2,sum[tp2]-sum[tmp.l-1],tmp.r+1,tmp.R}); 87 // cout<<"second"<<tmp.l<<" "<<tp2<<\' \'<<sum[tp2]-sum[tmp.l-1]<<\' \'<<tmp.r+1<<\' \'<<tmp.R<<endl; 88 } 89 } 90 printf("%lld",ans); 91 }
大视野百题留念
以上是关于[NOI2010]超级钢琴的主要内容,如果未能解决你的问题,请参考以下文章