0
点赞
收藏
分享

微信扫一扫

BZOJ 2006: [NOI2010]超级钢琴 RMQ 优先队列



2006: [NOI2010]超级钢琴


Time Limit: 20 Sec  Memory Limit: 552 MB

Submit: 3034  Solved: 1505

[Submit][Status][Discuss]

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。




求前k大的方案和

觉得这种东西一般都是把前k个都搞出来 像k短路一样

考虑枚举右端点,每次一定是取能使答案最大的左端点

用一个优先队列维护 

struct node{l,r,i,val}

l,r表示左端点取值范围 若l<=j<=r可使val最大

q.pop() q.push(l,j-1) q.push(j+1,r)

j的寻找用RMQ维护 (本蒟蒻RMQ数组开小 RE n 发)

就这么一顿搞 就OK啦


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>

using namespace std;

typedef double db;
typedef long long ll;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(ll x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=600100;

struct node{int l,r,i;ll val;};

inline bool operator < (const node &a,const node &b)
{return a.val<b.val;}

priority_queue<node>q;

int n,m,L,R,f[N][50],a[N];
ll sum[N];

void initial()
{
	register int i,j;
	for(i=1;i<=n;++i)f[i][0]=i;
	for(j=1;j<=log2(n);++j)for(i=0;i<=n;++i)
	{
		if(sum[f[i][j-1]]<sum[f[i+(1<<(j-1))][j-1]])
		f[i][j]=f[i][j-1];
		else f[i][j]=f[i+(1<<(j-1))][j-1];
	}
}

inline int query(int l,int r)
{
	int k=int(log2(r-l+1));
	int x=f[l][k],y=f[r-(1<<k)+1][k];
	return sum[x]<sum[y]?x:y;
}

int main()
{
	n=read();m=read();L=read();R=read();
	register int i,j,k,l,r;
	for(i=1;i<=n;++i)a[i]=read(),sum[i]=sum[i-1]+a[i];
	initial();
	for(i=L;i<=n;++i)
	{
		l=max(1,i-R+1);r=max(1,i-L+1);
		q.push((node){l,r,i,(sum[i]-sum[query(l-1,r-1)])});
	}
	ll ans=0;int cnt=0;node tmp;
	while(cnt<m)
	{
		tmp=q.top();q.pop();
		l=tmp.l;r=tmp.r;
		k=query(l-1,r-1);
		if(r>k+1)
		{
			j=query(k+1,r-1);
			q.push((node){k+2,r,tmp.i,(sum[tmp.i]-sum[j])});
		}
		if(l<k+1)
		{
			j=query(l-1,k-1);
			q.push((node){l,k,tmp.i,(sum[tmp.i]-sum[j])});
		}
		ans+=tmp.val;++cnt;
	}
	print(ans);puts("");return 0;
}
/*
4 3 2 3
3 2 -6 8

11
*/




举报

相关推荐

0 条评论