超级钢琴

题目:
小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。 这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。 一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。 小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最大值是多少。
输入格式:
第一行包含四个正整数n, k, L, R。其中n为音符的个数,k为乐曲所包含的超级和弦个数,L和R分别是超级和弦所 包含音符个数的下限和上限。 接下来n行,每行包含一个整数\(A_i\),表示按编号从小到大每个音符的美妙度。\(N\leq 500000\),\(k\leq 500000\),\(-1000\leq A_i\leq 1000\),\(1\leq L\leq R\leq N\)。且保证一定存在满足条件的乐曲
题解:
区间和可以用前缀和O(1)解决,然后前缀和用一个ST就可以A掉这道不算太难的题啦~
详见代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 0x7fffffff
#define ll long long
#define MAX 500005
using namespace std;
struct data{ int i,l,r,t; };
int Log[MAX],n,K,L,R,a[MAX],st[MAX][20];
ll ans;
void ST(){
	Log[0]=-1;for(int i=1;i<=n;i++)Log[i]=Log[i>>1]+1;
	for(int i=1;i<=n;i++)st[i][0]=i;
	for(int i=n;i;i--)for(int j=1;j<=18;j++)if(i+(1<<j)-1<=n){
		st[i][j]=a[st[i][j-1]]>a[st[i+(1<<(j-1))][j-1]]?st[i][j-1]:st[i+(1<<(j-1))][j-1];
	}
	else break;
}
int query(int l,int r){
	if(l==r)return l;
	int t=Log[r-l+1];
	int t1=st[l][t],t2=st[r-(1<<t)+1][t];
	return a[t1]>a[t2]?t1:t2;
}
bool operator<(data x,data y){
	return a[x.t]-a[x.i-1]<a[y.t]-a[y.i-1];
}
void solve(){
	priority_queue<data,vector<data> >q;
	for(int i=1;i<=n;i++)if(i+L-1<=n)
               q.push(data{i,i+L-1,min(n,i+R-1),query(i+L-1,min(n,i+R-1))});
	for(int i=1;i<=K;i++){
		data t=q.top();q.pop();
		ans+=a[t.t]-a[t.i-1];
		if(t.t-1>=t.l)q.push(data{t.i,t.l,t.t-1,query(t.l,t.t-1)});
		if(t.t+1<=t.r)q.push(data{t.i,t.t+1,t.r,query(t.t+1,t.r)});
	}
}
int main(){
	cin>>n>>K>>L>>R;
	for(int i=1;i<=n;i++)cin>>a[i],a[i]+=a[i-1];
	ST();
	solve();
	cout<<ans;
	return 0;
}

是不是非常简单?

posted @ 2019-09-18 17:09  鸡中翅  阅读(181)  评论(0编辑  收藏  举报