P2048 [NOI2010] 超级钢琴
P2048 [NOI2010] 超级钢琴
[NOI2010] 超级钢琴
题目描述
小 Z 是一个小有名气的钢琴家,最近 C 博士送给了小 Z 一架超级钢琴,小 Z 希望能够用这架钢琴创作出世界上最美妙的音乐。
这架超级钢琴可以弹奏出
一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于
小 Z 决定创作一首由
输入格式
输入第一行包含四个正整数
接下来
输出格式
输出只有一个整数,表示乐曲美妙度的最大值。
所有数据满足:
------------------------------------------------------------------------------------------------------
本来我以为我写过类似的题
P5283 [十二省联考 2019] 异或粽子
就能把轻松把这题A掉,但没学过RMQ的我还是年轻了qwq
首先介绍一下RMQ:
RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值。——OI Wiki
用我的话说这东西就是用倍增的思想维护一个st表
RMQ Code:
void get_len(){for(int i=0;i<lg;i++)len[i]=1<<i;} void get_st() { get_len(); for(int i=1;i<=n;i++)st[i][0]=i; for(int j=1;len[j]<=n;j++) { for(int i=1;i+len[j-1]-1<=n;i++) { int L=st[i][j-1],R=st[i+len[j-1]][j-1]; st[i][j]= sum[L]>sum[R] ? L : R; } } }
但有些不同的是,这里的st数组我维护的是sum值最大的的下标(对这题十分有用)
solution:
学完RMQ之后,本题的思路瞬间明确了:
我们维护一个前缀和,然后钦定一个点x,查询在合法长度区间 [l,r] 内, sum[pos] 的最大值,然后这个点的贡献显然就是 sum[pos]-sum[x-1]
至于维护贡献的方法那自然就是优先队列了捏~
在题面中可观察到:
两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。
然后我们仿照
P5283 [十二省联考 2019] 异或粽子
的思路:
在每个(x,[l,r])用完之后将其拆分为(x,[l,pos-1]),(x,[pos+1,r])
然后这题就做完了
那我们学的RMQ去哪了?
当然是维护“在合法长度区间 [l,r] 内, sum[pos] 的最大值”去了呗qwq
话说这个维护应该可以用线段树,可是多一个log还不太好写
况且我还懒
Code:
#include<bits/stdc++.h> #define int long long const int N=5e5+5; const int lg=20; using namespace std; int a[N],sum[N],st[N][lg],len[lg]; int n,k,L_lim,R_lim; void get_len(){for(int i=0;i<lg;i++)len[i]=1<<i;}//由于我觉得总写(1<<i)太难看 void get_st() { get_len(); for(int i=1;i<=n;i++)st[i][0]=i; for(int j=1;len[j]<=n;j++) { for(int i=1;i+len[j-1]-1<=n;i++) { int L=st[i][j-1],R=st[i+len[j-1]][j-1];//注意st表中的边界问题 st[i][j]= sum[L]>sum[R] ? L : R; } } } int query(int l,int r)// { int ll=log2(r-l+1); int L=st[l][ll],R=st[r-len[ll]+1][ll]; return sum[L]>sum[R] ? L : R; } struct Node{ int x,l,r,pos,val; Node(int x_=0,int l_=0,int r_=0) { x=x_,l=l_,r=r_; pos=query(l,r); val=sum[pos]-sum[x-1]; } bool operator <(const Node &n1)const{ return n1.val>val; } }; priority_queue<Node> Q; void work() { int ans=0; cin>>n>>k>>L_lim>>R_lim; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); sum[i]=sum[i-1]+a[i]; } get_st(); for(int i=1;i+L_lim-1<=n;i++) { int ll=i+L_lim-1,rr=min(i+R_lim-1,n); Q.push(Node(i,ll,rr)); }; for(int i=1;i<=k;i++) { Node u=Q.top();Q.pop(); ans+=u.val; if(u.l<=u.pos-1)Q.push(Node(u.x,u.l,u.pos-1)); if(u.pos+1<=u.r)Q.push(Node(u.x,u.pos+1,u.r)); } printf("%lld",ans); } #undef int int main() { freopen("P2048_1.in","r",stdin);//freopen("P2048.out","w",stdout); work(); }