2018.12.28-bzoj-2006-[NOI2010]超级钢琴
题目描述:
小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的
音乐。 这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。 一个“超级
和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的
所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。
小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。
我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最
大值是多少
算法标签:st表
思路:
对于以每个节点为左节点的区间,用st表求出最优的右区间,用优先队列维护,每次取出队首的同时,把区间以上一次最优点为分界分成两半继续进队列。
以下代码:
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=5e5+5; struct node{int x,l,r,pos,v;friend bool operator<(node t1,node t2) {return t1.v<t2.v;}}; int n,k,L,R,sum[N],mx[N][20],Log[N];long long ans;priority_queue<node> q; il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;} il int Max(int x,int y){return sum[x]<sum[y]?y:x;} il int query(int l,int r){int k=Log[r-l+1];return Max(mx[l][k],mx[r-(1<<k)+1][k]);} int main() { n=read();k=read();L=read();R=read(); for(int i=1;i<=n;i++)sum[i]=sum[i-1]+read(),mx[i][0]=i; for(int i=2;i<=n;i++)Log[i]=Log[i>>1]+1; for(int j=1;j<=Log[n];j++)for(int i=1;i+(1<<j-1)<=n;i++) mx[i][j]=Max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]); for(int i=1;i+L-1<=n;i++){ int pos=query(i+L-1,min(i+R-1,n));q.push((node){i,i+L-1,min(i+R-1,n),pos,sum[pos]-sum[i-1]}); } while(k--){ node now=q.top();q.pop();ans+=now.v;int p; if(now.l<now.pos)p=query(now.l,now.pos-1),q.push((node){now.x,now.l,now.pos-1,p,sum[p]-sum[now.x-1]}); if(now.pos<now.r)p=query(now.pos+1,now.r),q.push((node){now.x,now.pos+1,now.r,p,sum[p]-sum[now.x-1]}); } printf("%lld\n",ans); return 0; }