●BZOJ 2006 NOI 2010 超级钢琴

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=2006

题解:

RMQ + 优先队列 (+ 前缀)

记得在一两个月前,一次考试考了这个题目的简化版:序列中只有正整数。
当时我们曰 :有负数的话就怕是莫得解法哦。
然后,有负数的情况居然是NOI题。。。
难哭。

1).首先尝试固定区间的右端点R。
那么可取的左端点的范围就已经确定。
所以对于右端点为 R的权和最大的区间就能够求出来了:
先求出前缀序列 pre[],
由于 sum = pre[R]-pre[L-1],且 pre[R] 固定,
即我们需要求出合法范围内的最小的 pre[L-1],
这个就可以用 RMQ实现。

2).用优先队列维护。
初始化时,把每个右端点R的最大权和区间的相关信息放入队列:
保存这些信息 :
{sum(该区间的和),R(固定的区间右端点是谁),p(区间和为sum时对应的左端点),l(左端点的左界),r(左端点的右界)}
那么直接取堆顶,即是当前的最大权和区间。
然后接下呢,为了以后不重复取到当前区间,我们把 [l,r] 剖成 [l,p-1] 和 [p+1,r]
并计算出相应的信息,继续放入优先队列,即把
{sum1,R,p1,l,p-1} 和  {sum2,R,p2,p+1,r} 加入进去。
重复操作 K次即可。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 500005
#define ll long long
using namespace std;
struct info{
	ll sum,R,p,l,r;
	bool operator <(const info & rtm) const{
		return sum<rtm.sum;
	}
};
ll stv[MAXN][20],stp[MAXN][20],log2[MAXN];
ll pre[MAXN],N,K,A,B,ans;
priority_queue<info>q;
ll query(ll l,ll r){
	static ll k,mini;
	k=log2[r-l+1];
	mini=min(stv[l+(1<<k)-1][k],stv[r][k]);
	if(stv[l+(1<<k)-1][k]==mini) return stp[l+(1<<k)-1][k];
	else return stp[r][k];
}
int main()
{
	freopen("piano.in","r",stdin);
	freopen("piano.out","w",stdout);
	log2[1]=0; ll pos; info now;
	for(ll i=2;i<=MAXN-5;i++) log2[i]=log2[i>>1]+1;
	scanf("%lld%lld%lld%lld",&N,&K,&A,&B);
	for(ll i=1;i<=N;i++)
		scanf("%lld",&pre[i]),pre[i]+=pre[i-1],stv[i][0]=pre[i],stp[i][0]=i;
	for(ll k=1;k<=log2[N];k++)
		for(ll i=(1<<k)-1;i<=N;i++){
			stv[i][k]=min(stv[i][k-1],stv[i-(1<<(k-1))][k-1]);
			if(stv[i][k-1]==stv[i][k]) stp[i][k]=stp[i][k-1];
			else stp[i][k]=stp[i-(1<<(k-1))][k-1];
		}
	for(ll i=1,lmin,lmax;i<=N;i++){
		lmin=max(1ll,i-B+1); lmax=max(0ll,i-A+1);
		if(lmax==0) continue;
		pos=query(lmin-1,lmax-1)+1;
		q.push((info){pre[i]-pre[pos-1],i,pos,lmin,lmax});
	}
	while(K--){
		now=q.top(); q.pop();
		ans+=now.sum;
		if(now.p-1>=now.l){
			pos=query(now.l-1,now.p-1-1)+1;
			q.push((info){pre[now.R]-pre[pos-1],now.R,pos,now.l,now.p-1});
		}
		if(now.r>=now.p+1){
			pos=query(now.p+1-1,now.r-1)+1;
			q.push((info){pre[now.R]-pre[pos-1],now.R,pos,now.p+1,now.r});
		}
	}
	printf("%lld",ans);
	return 0;
}
时间: 2024-10-12 01:48:24

●BZOJ 2006 NOI 2010 超级钢琴的相关文章

BZOJ 2006 NOI 2010 超级钢琴 堆+主席树

题目大意:给出一些音符,将它们组成和旋.和旋只能由[l,r]个音符组成.优美程度为所有音符的和.求k个和旋的又优美程度的最大和. 思路:先处理出来前缀和,以便O(1)去除一段的和.然后考虑对于一个音符来说,向左边扩展的音符是一段长度为r - l + 1的区间,取出的最大和是sum[i] - sum[p],sum[i]是一定的,要想让整段和最大,需要让sum[p]最小.之后就是区间k小值和堆得维护了,可以用时代的眼泪划分树,也可以用主席树. CODE: #include <vector> #in

[NOI 2010]超级钢琴

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

【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 2007 NOI 2010 海拔 平面图最小割-&gt;最短路SPFA+pq

题目大意:给出一个城市各个道路的双向流量,城市的左上角的高度是0,城市的右下角的高度是1,若人流升高海拔就会消耗体力,问最小需要消耗多少体力. 思路:这道题才是真正的让我见识到了algorithm中的heap的强大. 分析这道题可以发现,一定会有一条分界线,这个分界线左边高度都为0,右边高度都是1,然后找到这条分界点就可以了.明显的最小割.但是数据量巨大,直接跑最大流会T,又是平面图,建立对偶图然后跑最短路,SPFA+pq在BZOJ上可以很快,如果有的OJ卡STL的话可以考虑SPFA+Heap,

●BZOJ 2005 NOI 2010 能量采集

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2005 题解: 一个带有容斥思想的递推.%%% 首先,对于一个点 (x,y) 在路径 (0,0)->(x,y)上,经过的点数为 GCD(x,y)-1所以改点的贡献为 2*GCD(x,y)-1            N    M那么,ANS = ∑    ∑(2*GCD(i,j)-1)           i=1 j=1显然超时.考虑到 GCD<=100000,那么是否可以求出 f[i] 表

2006: [NOI2010]超级钢琴 - BZOJ

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

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

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

BZOJ 2006: [NOI2010]超级钢琴

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

BZOJ 2006: [NOI2010]超级钢琴( RMQ + 堆 )

取最大的K个, 用堆和RMQ来加速... ----------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; typedef long long ll; typedef pair<int, int> p