【BZOJ2006】[NOI2010]超级钢琴 ST表+堆

【BZOJ2006】[NOI2010]超级钢琴

Description

小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。 这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。 一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。 小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最大值是多少。

Input

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

包含音符个数的下限和上限。 接下来n行,每行包含一个整数Ai,表示按编号从小到大每个音符的美妙度。

N<=500,000

k<=500,000

-1000<=Ai<=1000,1<=L<=R<=N且保证一定存在满足条件的乐曲

Output

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

Sample Input

4 3 2 3
3
2
-6
8

Sample Output

11
【样例说明】
共有5种不同的超级和弦:
音符1 ~ 2,美妙度为3 + 2 = 5
音符2 ~ 3,美妙度为2 + (-6) = -4
音符3 ~ 4,美妙度为(-6) + 8 = 2
音符1 ~ 3,美妙度为3 + 2 + (-6) = -1
音符2 ~ 4,美妙度为2 + (-6) + 8 = 4
最优方案为:乐曲由和弦1,和弦3,和弦5组成,美妙度为5 + 2 + 4 = 11。

题解:一开始想用主席树,然后越想越觉得做麻烦了,于是看题解发现用ST表就行。

我们先考虑较暴力的写法(最暴力的肯定是n2logn),假如我们已经确定了所选区间的右端点,那么我们能否快速知道最优的左端点是哪个呢?显然可以,我们将区间和转变为前缀相减的形式,求[l,r]的最大值也就是求s[r]-s[l-1]的最大值,因为r确定,而l只能在一段固定的区间,我们可以用ST表快速查询最小值。然后我们对于每个可行的右端点都找出最优的左端点,把它们扔到优先队列里一个一个取出来就行了。

但是问题来了,加入我们取出了点x,它的最优最短点y,那么在我们取出了y后,以后就不能再取y这个点了,那么我们该怎样将y删除呢?一个naive的想法就是用主席树,但是这要麻烦不少。

我们的目的就是想办法避免删除操作(因为ST表是不支持修改的),我们发现,加入原来x的左端点可以在[a,b]中选择,我们与其从[a,b]中去掉y,不如将[a,b]分裂成[a,y-1]和[y+1,b]两段,然后将这两段都扔到优先队列中。也就是说,我们在优先队列中存放的其实是一个四元组(sum,x,a,b),分别代表区间和,右端点,合法左端点的区间最左边和最右边。

代码真的巨短。

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#include <utility>
#define mp(A,B,C,D)	make_pair(make_pair(A,B),make_pair(C,D))
using namespace std;
typedef pair<int,int> pii;
priority_queue<pair<pii,pii> > pq;
int n,m,L,R;
long long ans;
const int maxn=500010;
int sn[maxn][20],v[maxn],s[maxn],Log[maxn];
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
int mn(int a,int b)
{
	return s[a]<s[b]?a:b;
}
int query(int a,int b)
{
	if(a>b)	return -1;
	int k=Log[b-a+1];
	return mn(sn[a][k],sn[b-(1<<k)+1][k]);
}
int main()
{
	n=rd(),m=rd(),L=rd(),R=rd();
	int i,j,x,y,a,b,c,d;
	for(i=2;i<=n;i++)	Log[i]=Log[i>>1]+1;
	for(i=1;i<=n;i++)	sn[i][0]=i,v[i]=rd(),s[i]=v[i]+s[i-1];
	for(j=1;(1<<j)<=n;j++)
		for(i=0;i+(1<<j)-1<=n;i++)
			sn[i][j]=mn(sn[i][j-1],sn[i+(1<<j-1)][j-1]);
	for(i=L;i<=n;i++)	pq.push(mp(s[i]-s[query(max(i-R,0),i-L)],i,max(i-R,0),i-L));
	for(i=1;i<=m;i++)
	{
		pii t1=pq.top().first,t2=pq.top().second;
		ans+=t1.first,x=t1.second,a=t2.first,b=t2.second,y=query(a,b),pq.pop();
		c=query(a,y-1),d=query(y+1,b);
		if(c!=-1)	pq.push(mp(s[x]-s[c],x,a,y-1));
		if(d!=-1)	pq.push(mp(s[x]-s[d],x,y+1,b));
	}
	printf("%lld",ans);
	return 0;
}
时间: 2024-10-23 22:23:41

【BZOJ2006】[NOI2010]超级钢琴 ST表+堆的相关文章

[BZOJ2006][NOI2010]超级钢琴(ST表+堆)

2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3679  Solved: 1828[Submit][Status][Discuss] Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中Ai可正可负. 一个“超级 和弦”由若干个编号连续的音符组成,

2006: [NOI2010]超级钢琴|ST表|堆

由于K很小,所以就直接取出最大的K个值加起来即可 考虑一个(i,l,r)表示以i开始以[l,r]中的某个位置结束的区间和的最大值,假设这个位置为p,然后把这些东西都存起来一起扔到堆中,每次取出区间和最大的一个元素,然后继续向堆中添加新的元素,直接对(i,l,p?1),(i,p+1,r)这两个组合再分别找出最大的区间和再扔到堆中,然后重复此过程直到找出前K大 (i,l,r)组合的最大区间和为max(sum[l],sum[l+1]...sum[r])?sum[i?1],找(i,l,r)组合的最大区间

[NOI2010]超级钢琴 划分树+堆

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; #define N 510000 struct P{ int x,y; P(int a=0,int b=0){x=a,y=b;} bool operator<(P a)const{ return y<a.y; } }

[BZOJ2006] [NOI2010]超级钢琴 主席树+贪心+优先队列

2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 3591  Solved: 1780[Submit][Status][Discuss] Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中Ai可正可负. 一个"超级 和弦"由若干个编号连续的

bzoj2006 noi2010 超级钢琴 主席树 + 优先队列

Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2435  Solved: 1195 Description 小 Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中Ai可正可负. 一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R.我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和.两

bzoj2006 [NOI2010]超级钢琴 [优先队列|RMQ]

Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中Ai可正可负. 一个"超级和弦"由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R.我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和.两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的. 小Z决定创作一首由k个超级和弦组成的乐曲,为了使得

bzoj2006 [NOI2010]超级钢琴

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2006 [题解] 思路巧妙啊! 前置技能:序列和可以转化成前缀和的形式,那么前缀和左端点固定了右端点就是区间找最大值了. 记录五元组(from, l, r, pos, val)表示从from开始,右端点在[l,r]之间,在pos处取max,取max的值是val. 那么按照val扔到堆里,每次取出最大的,从pos分裂成两半,要兹磁求最大值,所以st表就行了. # include <queue>

【BZOJ 2006】[NOI2010]超级钢琴 ST

我们先把所有最左端对应的最优右端入堆,eg: z  在[l,r](由题目给出的L,R决定)之间的最优解 y,然后出堆以后,再入堆z,y-1,z,y+1,那么我们只需要用st找最大前缀和就好了(ST是一种用来解决RMQ问题的方法他的应用也就限于此了) #include <cstdio> #include <cstring> #include <queue> #define make(a,b,c,d) (DT){a,b,c,d} #define MAXN 500000 us

BZOJ 2006 NOI2010 超级钢琴 划分树+堆

题目大意:给定一个序列,找到k个长度在[l,r]之间的序列,使得和最大 暴力O(n^2logn).肯定过不去 看到这题的第一眼我OTZ了一下午...后来研究了非常久别人的题解才弄明确怎么回事...蒟蒻果然不能理解大神的思路啊0.0 首先维护前缀和,那么以第i个元素结尾的和最大的序列自然就是sum[i]-min{sum[j]}(i-r<=j<=i-l) 然后我们维护一个大根堆.每取走一个以i为结尾的元素,增加sum[i]-2thmin{sum[j]},再取走这个元素就增加sum[i]-3thmi