[Question Solution] Luogu P2048 [NOI2010] Super Piano

Go to: My own blog

topic

Luogu P2048[NOI2010] Super Piano

answer

After the problem is simplified, find the subintervals with the top k largest. First find the prefix and s[], enumerate the left end point l of the subinterval, and then find the optimal right end point r (ie enumerate s[l-1], then find the largest s[r] that meets the conditions), find The process of the largest s[r] is the process of finding the maximum value of the static interval, using the ST table. Put the sub-intervals found in the previous step into the priority queue for maintenance, and then take out an interval and the largest element each time, count them into the answer, and find the second largest interval with the same left end point and s[r]. When finding the second largest s[r], you only need to find the position of the largest s[r] first, and then use the ST table to find the maximum value of s[r] on its left and right sides, and then use them as candidates The answer is added to the priority queue.

Code

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
typedef long long ll;
int n,k,L,R;
int s[maxn],f[maxn][20],lg2[maxn];
struct music{int l,rmin,rmax,max_p,sum;};
//一个music表示一个和弦,即一个子区间
//l表示区间左端点-1,max_p表示从范围[rmin,rmax]中求出的最大的s[r]的下标,sum表示区间和 
priority_queue<music> q;
bool operator <(const music &x,const music &y) {return x.sum<y.sum;} //注意重载小于号 
inline int read()
{
	int s=0,f=1; char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s*f;
}
inline void get_ST() //维护最值,改成维护最值的下标 
{
	for(int i=1;i<=n;i++) f[i][0]=i;
	for(int i=2;i<=n;i++) lg2[i]=lg2[i>>1]+1;
	for(int j=1;(1<<j)<=n;j++)
		for(int i=1;i+(1<<j)-1<=n;i++)
			f[i][j]=s[f[i][j-1]]>s[f[i+(1<<(j-1))][j-1]] ? f[i][j-1] : f[i+(1<<(j-1))][j-1];
}
inline int RMQ(int l,int r)
{
	int t=lg2[r-l+1];
	return s[f[l][t]]>s[f[r-(1<<t)+1][t]] ? f[l][t] : f[r-(1<<t)+1][t];
}
inline void solve()
{
	for(int i=0;i+L<=n;i++) //枚举区间左端点-1(s[l-1]) 
	{
		int l=i+L,r=min(i+R,n); //此处l,r表示区间右端点的位置范围 
		q.push((music){i,l,r,RMQ(l,r),s[RMQ(l,r)]-s[i]});
	}
	ll ans=0;
	for(int i=1;i<=k;i++)
	{
		music x=q.top(); q.pop(); ans+=(ll)x.sum;
		if(x.rmin<=x.max_p-1) q.push((music){x.l,x.rmin,x.max_p-1,RMQ(x.rmin,x.max_p-1),s[RMQ(x.rmin,x.max_p-1)]-s[x.l]});
		if(x.rmax>=x.max_p+1) q.push((music){x.l,x.max_p+1,x.rmax,RMQ(x.max_p+1,x.rmax),s[RMQ(x.max_p+1,x.rmax)]-s[x.l]});
	}	//注意判断合法性 
	printf("%lld\n",ans);
}
	
int main()
{
	n=read(),k=read(),L=read(),R=read();
	for(int i=1;i<=n;i++) s[i]=s[i-1]+read();
	get_ST(); solve();
	
	return 0;
}

Guess you like

Origin blog.csdn.net/zjgmartin/article/details/108415172