【bzoj2006】超级钢琴

Portal --> bzoj2006

Solution

  一开始看错题了。。没有看到编号连续然后愣了好久==

​  首先肯定是找最大的\(K\)个啦,然后具体怎么找的话。。没有什么特别好的办法那就暴力一点,每次取最大值然后把它删掉然后再取这样

​  现在的问题是怎么找最大值

​  注意到一个很重要的点,因为这题要求一个和弦的音符编号是连续的一段(一个区间),所以我们可以按照区间的左端点分类,每一类形如\((st,l,r)\),表示左端点为\(st\),右端点\(\in[l,r]\)的区间集合,显然,当前的最大值一定是每一类最大值的最大值,那么如果说我们知道了每一类的最大值之后,将所有的类全部丢进一个堆里面就好了,至于删除的话,如果说我们可以定位这个最大值具体是哪个区间(假设为\([lx,rx]\)),那么我们只要把这个区间所在的类\((st,l,r)\)先删掉,然后再把\((st,l,lx-1)\)\((st,rx+1,r)\)加进去就好了

​  那么最后的问题就是我们要寻求一种快速的计算\((st,l,r)\)这类区间的最大值的办法

​  既然是区间求和。。那当然是用前缀和啊,然后发现因为对于一类区间来说,左端点是固定的,所以我们只要比较这类区间中右端点处的前缀和即可比较大小,所以我们直接ST表RMQ一下就好了,这样也能很方便地定位具体是哪个区间

​  具体实现的话,可以每个类多加一个参数\(mx\),表示这类区间中区间和最大的那个区间为\([st,mx]\),然后。。堆里面的话各类区间比较的时候根据\(sum[mx]-sum[st-1]\)的大小比较就好了

  

​  mark:看清楚题目(是求和还是求第\(K\)大,是连续还是不连续,是否需要用long long)

​  mark:区间的问题的话。。是不是固定其中一点是套路。。?

  

​  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#define ll long long
using namespace std;
const int N=500010,TOP=20;
ll sum[N],a[N],mx[N][TOP+1];
struct Data{
	int st,l,r,mx;
	Data(){}
	Data(int st1,int l1,int r1,int mx1){st=st1; l=l1; r=r1; mx=mx1;}
	friend bool operator < (Data x,Data y){return sum[x.mx]-sum[x.st-1]<sum[y.mx]-sum[y.st-1];}
};
priority_queue<Data> q;
int n,m,L,R,K;
ll ans;
void prework(){
	for (int i=1;i<=n;++i) mx[i][0]=i;
	for (int j=1;j<=TOP;++j)
		for (int i=n-(1<<j)+1;i>=1;--i)
			if (sum[mx[i][j-1]]>sum[mx[i+(1<<j-1)][j-1]])
				mx[i][j]=mx[i][j-1];
			else 
				mx[i][j]=mx[i+(1<<j-1)][j-1];
}
int get_mx(int l,int r){
	int len=r-l+1,lg=(int)(log(1.0*len)/log(2.0));
	if (sum[mx[l][lg]]>sum[mx[r-(1<<lg)+1][lg]]) return mx[l][lg];
	return mx[r-(1<<lg)+1][lg];
}
void solve(){
	Data tmp;
	while (!q.empty()) q.pop();
	for (int i=1;i+L-1<=n;++i)
		q.push(Data(i,i+L-1,min(i+R-1,n),get_mx(i+L-1,min(i+R-1,n))));
	ans=0;
	for (int i=1;i<=K;++i){
		if (q.empty()) break;
		tmp=q.top(); q.pop();
		ans+=sum[tmp.mx]-sum[tmp.st-1];
		//printf("%d\n",ans);
		if (tmp.l<=tmp.mx-1)
			q.push(Data(tmp.st,tmp.l,tmp.mx-1,get_mx(tmp.l,tmp.mx-1)));
		if (tmp.mx+1<=tmp.r)
			q.push(Data(tmp.st,tmp.mx+1,tmp.r,get_mx(tmp.mx+1,tmp.r)));
	}
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	scanf("%d%d%d%d",&n,&K,&L,&R);
	sum[0]=0;
	for (int i=1;i<=n;++i) scanf("%lld",a+i),sum[i]=sum[i-1]+a[i];
	prework();
	solve();
	printf("%lld\n",ans);
}
posted @ 2018-10-17 16:11  yoyoball  阅读(176)  评论(0编辑  收藏  举报