Yurchiu's Blog

P2048 [NOI2010] 超级钢琴

Yurchiu 2020-12-03, 01:34:54 935 隐藏左右两栏 展示左右两栏

题解 P2048 [NOI2010]超级钢琴

题面

有一数列,包含nn 个数,编号为 11nn 。第 ii 个数权值为 AiA_i

我们要找到 kk 段连续子序列,满足其中数的数量 xx 保证 LxRL\leq x\leq R ,求这 kk 段序列中所有数字的权值和的最大值。

所有数据满足:1000Ai1000-1000 \leq A_i \leq 10001LRn1 \leq L \leq R \leq n1n,k5000001 \le n,k \le 500000 ,且保证一定有解。

题解

可以想到,求区间和用前缀和。使用贪心思想来解决这个问题。

fi(l,r)f_i(l,r) 表示以 ii 为左端点,右端点在 [l,r][l,r] 区间中,序列的最大值。设 s(i)s(i) 是前缀和。

fi(l,r)=s(xi)s(i1)f_i(l,r)=s(x_i)-s(i-1)。其中 xi[l,r]x_i \in [l,r],使 fi(l,r)f_i(l,r) 最大。

那么就要求 xix_i。由于 s(i1)s(i-1) 值固定,也就是求 s(xi)s(x_i) ,也就是求区间最大值(前缀和数组),可以用 st 表解决。


求得对于所有 i[1,n]i\in[1,n] ,满足使 fi(l,r)f_i(l,r) 的值最大的 xix_i 后,把这些相关值(iillrrxix _ifi(l,r)f_i(l,r))搞成结构体,放入一个堆中。

循环 kk 次,每次取最大的 fi(l,r)f_i(l,r) ,把 fi(l,r)f_i(l,r) 累加起来。

取完后,可能还有次优 xx 值存在于 [l,r][l,r]。故也要求使 fi(l,xi1)f_i(l,x_i-1)fi(xi+1,r)f_i(x_i+1,r) 的值最大的对应 xx 值,把求解过程中的相关值也放入堆(即在区间 [l,r][l, r] 排除了 $x_i $)。

累加起来的值即为答案。

代码

#include<bits/stdc++.h>
using namespace std;
namespace _yz
{
	const int N=600000+5,log=19;
	struct music{int s,l,r,a;};//采用四元组,表示i,l,r,xi。fi(l,r) 现场求即可。
	int n,k,L,R,b[N],st[25][N];
	long long ans=0,a[N];
	priority_queue<music>q;
	bool operator<(music x,music y){return a[x.a]-a[x.s-1]<a[y.a]-a[y.s-1];}
	int query(int l,int r)
	{
		int len=r-l+1;
		if(a[st[b[len]][l]]>a[st[b[len]][r+1-(1<<b[len])]])
			return st[b[len]][l];
		return st[b[len]][r+1-(1<<b[len])];
	}
	void yzmain()
	{
		scanf("%d%d%d%d",&n,&k,&L,&R);
		for(int i=1;i<=n;i++) scanf("%lld",a+i),a[i]+=a[i-1];
		for(int i=1;i<=n;i++) st[0][i]=i;//st 表存的是 xi
		for(int i=1;i<=log;i++) b[1<<i]=1;
		for(int i=1;i<=n;i++) b[i]+=b[i-1];
		for(int i=1;i<=log;i++)
			for(int j=1;j<=n;j++)
				if(a[st[i-1][j]]>a[st[i-1][j+(1<<(i-1))]])
					st[i][j]=st[i-1][j];
				else
					st[i][j]=st[i-1][j+(1<<(i-1))];
		for(int i=1;i<=n;i++) 
			if(i+L-1<=n) q.push((music){i,i+L-1,min(i+R-1,n),query(i+L-1,min(i+R-1,n))});//注意不要超出 n
		for(int i=1;i<=k;i++)
		{
			music now=q.top();q.pop();
			ans+=a[now.a]-a[now.s-1];//计算 fi(l,r) 
			if(now.a!=now.l) q.push((music){now.s,now.l,now.a-1,query(now.l,now.a-1)});
			if(now.a!=now.r) q.push((music){now.s,now.a+1,now.r,query(now.a+1,now.r)});
		}
		printf("%lld\n",ans);
		return;
	}
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	_yz::yzmain();
	return 0;
}




本文作者:Yurchiu

本文链接:https://yz-hs.github.io/1a6156b5845c/

版权声明:本博客中所有原创文章除特别声明外,均允许规范转载,转载请注明出处。所有非原创文章,按照原作者要求转载。


By Yurchiu.
其他物件杂物收纳
Hitokoto

Yurchiu 说,除了她以外的人都很强!嘤嘤嘤~~
博客信息
文章数目
158
最近更新
08-21
本站字数
350.6k
文章目录