题目分析
简单地说,题目就是让我们找出前k大的大小在l~r之间的区间。
因为每段和弦都是连续的,而区间美妙度为所包括的音符的美妙度之和,所以可以使用前缀和来优化。
有个最朴素的想法就是,我们把所有大小在l~r之间的区间全部抽出来排序。但这样复杂度太大了,明显无法通过,所以考虑如何优化。
既然我们要找前k大的,一遍全找出来不好找,那么每次只找一个最优的呢?
想一下,应该是可做且正确的,那么到底怎么找呢?
首先对于每个点i,我们找到满足条件的且美妙度最大的j配对,然后加到一个堆里,这样首先保证了第一个从堆顶弹出的是整个序列的合法区间最大值。
那之后怎么办呢?对于弹出的区间,它还可以扩展啊。j 是在 i+L-1 ~ i+R-1 之间的,显然对于弹出的这个区间,我们还可以把它分成 i~p1 ( i+L-1<= p1 < j ) 的区间和 i~p2 ( j+1 <= p2 <= i+R-1)。
所以我们要做的事情,就是要找能使这两个区间最大的p1和p2的位置。
求使区间和我们会做,只要RMQ就可以,那么求使区间和最大的位置,当然也可以通过此过程做出来了。
当然,因为我们有前缀和,所以直接可以在RMQ的过程中比较出哪个位置更优,所以RMQ中直接存使它对应的那段区间中最优的位置就行了。
(详见代码)
1 #include<bits/stdc++.h> 2 #define INTMAX 2147483647LL 3 #define PII pair<int,int> 4 #define MK make_pair 5 #define re register 6 using namespace std; 7 typedef long long ll; 8 const double Pi=acos(-1.0); 9 const int Inf=0x3f3f3f3f; 10 const int MAXN=5e5+10; 11 inline int read(){ 12 re int x=0,f=1,ch=getchar(); 13 while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar(); 14 while(isdigit(ch))x=x*10+ch-48,ch=getchar(); 15 return x*f; 16 } 17 inline ll readll(){ 18 re ll x=0,f=1,ch=getchar(); 19 while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar(); 20 while(isdigit(ch))x=x*10+ch-48,ch=getchar(); 21 return x*f; 22 } 23 24 struct Node{ 25 int ll,rr,idl,idr,val; 26 inline bool operator <(const Node &x)const{ 27 return x.val>val; 28 } 29 }; 30 31 ll ans; 32 int n,k,L,R; 33 int a[MAXN],sum[MAXN]; 34 int RMQ[MAXN][21]; 35 priority_queue<Node> q; 36 inline int Query(int l,int r){ 37 int k=log2(r-l+1); 38 int x=RMQ[l][k],y=RMQ[r-(1<<k)+1][k]; 39 return sum[x]>sum[y]?x:y; 40 } 41 int main(){ 42 n=read();k=read();L=read();R=read(); 43 for(int i=1;i<=n;++i){ 44 a[i]=read(); 45 sum[i]=sum[i-1]+a[i]; 46 RMQ[i][0]=i; 47 } 48 for(int j=1;(1<<j)<=n;++j) 49 for(int i=1;i+(1<<j)-1<=n;++i){ 50 int x=RMQ[i][j-1],y=RMQ[i+(1<<(j-1))][j-1]; 51 if(sum[x]>sum[y]) RMQ[i][j]=x; 52 else RMQ[i][j]=y; 53 } 54 55 for(int i=1;i<=n;++i) 56 if(i+L-1<=n){ 57 int p=Query(i+L-1,min(i+R-1,n)); 58 q.push(Node{i+L-1,min(i+R-1,n),i,p,sum[p]-sum[i-1]}); 59 } 60 for(int i=1;i<=k;++i){ 61 Node x=q.top();q.pop(); 62 ans+=(ll)x.val; 63 if(x.ll!=x.idr){ 64 int p=Query(x.ll,x.idr-1); 65 q.push((Node){x.ll,x.idr-1,x.idl,p,sum[p]-sum[x.idl-1]}); 66 } 67 if(x.rr!=x.idr){ 68 int p=Query(x.idr+1,x.rr); 69 q.push((Node){x.idr+1,x.rr,x.idl,p,sum[p]-sum[x.idl-1]}); 70 } 71 } 72 printf("%lld ",ans); 73 return 0; 74 }