luogu P2048 [NOI2010] 超级钢琴 |堆+RMQ

题目描述

小 Z 是一个小有名气的钢琴家,最近 C 博士送给了小 Z 一架超级钢琴,小 Z 希望能够用这架钢琴创作出世界上最美妙的音乐。

这架超级钢琴可以弹奏出 (n) 个音符,编号为 (1)(n)。第 (i) 个音符的美妙度为 (A_i)​,其中 (A_i) 可正可负。

一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于 (L) 且不多于 (R)。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。

小 Z 决定创作一首由 (k) 个超级和弦组成的乐曲,为了使得乐曲更加动听,小 Z 要求该乐曲由 (k) 个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小 Z 想知道他能够创作出来的乐曲美妙度最大值是多少。

输入格式

输入第一行包含四个正整数 (n, k, L, R)。其中 (n) 为音符的个数,(k) 为乐曲所包含的超级和弦个数,(L)(R) 分别是超级和弦所包含音符个数的下限和上限。

接下来 (n) 行,每行包含一个整数 (A_i)​,表示按编号从小到大每个音符的美妙度。

输出格式

输出只有一个整数,表示乐曲美妙度的最大值。

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5e5+5;
#define int long long
int n,k,L,R,sum[N],Log[N];
struct node{
	int x,l,r,t,id;
	bool operator < (const node &rhs)const{
		return t<rhs.t;
	}
};
priority_queue<node>Q;
struct mzx{
	int x,id;
}f[N][21];
inline mzx Min(mzx a,mzx b){
	if(a.x < b.x) return a;
	else return b;
}
inline mzx getmin(int l,int r){
	int len=Log[r-l+1];
	return Min(f[l][len],f[r-(1<<len)+1][len]);
}
signed main(){
	cin>>n>>k>>L>>R;
	Log[0]=-1;
	f[0][0].id=0;
	for(int i=1;i<=n;i++){
		scanf("%lld",&f[i][0].x);
		f[i][0].x+=f[i-1][0].x;
		Log[i]=Log[i>>1]+1;
		f[i][0].id=i;
		sum[i]=f[i][0].x;
	}
	for(int j=1;j<=20;j++)
	for(int i=0;i+(1<<j)-1<=n;i++)
	f[i][j]=Min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
	Log[0]=1;
	
	for(int i=L,l,r;i<=n;i++){
		l=max(i-R,0ll),r=i-L;
		mzx op=getmin(l,r);
		node t=(node){i,l,r,sum[i]-op.x,op.id};
		Q.push(t);
	}
	int ans=0,l,r,id;
	mzx op;
	while(k--){
		node t=Q.top(); Q.pop();
		ans+=t.t; 
		int x=t.x, l=t.l, r=t.r, id=t.id;
		if(l<=id-1){
			op=getmin(l,id-1);
			Q.push((node){x,l,id-1,sum[x]-op.x,op.id});
		}
		if(id+1<=r){
			op=getmin(id+1,r);
			Q.push((node){x,id+1,r,sum[x]-op.x,op.id});
		}
	}
	cout<<ans<<endl;

}
不以物喜,不以己悲
原文地址:https://www.cnblogs.com/naruto-mzx/p/15365449.html