记录编号 60518 评测结果 AAAAAAAAAA
题目名称 [NOI 2010]超级钢琴 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 3.171 s
提交时间 2013-05-26 11:58:15 内存使用 75.82 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<map>
#include<set>
#include<vector>
#include<cstring>
#include<queue>
#include<deque>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const ll SIZEN=500010;
ll n,k;
ll a[SIZEN]={0};
ll s[SIZEN]={0};
ll f[SIZEN][20]={0};//ST,但里面存的是最大值的位置
ll min(ll a,ll b){
	return a<b?a:b;
}
void ST_init(ll a[SIZEN]){
	ll m=floor(log((double)n)/log(2.0));
	ll i,j;
	for(i=1;i<=n;i++) f[i][0]=i;
	for(j=1;j<=m;j++){
		for(i=1;i<=n;i++){
			if(i+(1<<j)-1>n) continue;
			f[i][j]=f[i][j-1];
			if(a[f[i+(1<<(j-1))][j-1]]>a[f[i][j]]) f[i][j]=f[i+(1<<(j-1))][j-1];
		}
	}
}
ll rmq(ll l,ll r){//这里返回的是位置
	ll m=floor(log((double)(r-l+1))/log(2.0));
	if(s[f[l][m]]>s[f[r-(1<<m)+1][m]]) return f[l][m];
	else return f[r-(1<<m)+1][m];
}
class NODE{
public:
	ll pos;
	ll l,r;
	ll num;
	//这样四个数表示:在左端点为pos,右端点在[l,r]之间的所有和弦的最大值num
	ll ind;//最大值的标号
	void calc(void){
		ind=rmq(l,r);
		num=s[ind]-s[pos-1];
	}
};
bool operator < (NODE a,NODE b){
	return a.num<b.num;
}
priority_queue<NODE> Q;
ll ans=0;
void work(void){
	ll i;
	NODE x,y,z;
	for(i=1;i<=k;i++){
		x=Q.top();Q.pop();
		ans+=x.num;
		y.pos=z.pos=x.pos;
		y.l=x.l,z.r=x.r;
		y.r=x.ind-1,z.l=x.ind+1;
		if(y.r>=y.l){
			y.calc();
			Q.push(y);
		}
		if(z.r>=z.l){
			z.calc();
			Q.push(z);
		}
	}
}
void init(void){
	ll L,R;
	scanf("%lld%lld%lld%lld",&n,&k,&L,&R);
	ll i;
	for(i=1;i<=n;i++){
		scanf("%lld",&a[i]),s[i]=s[i-1]+a[i];
	}
	ST_init(s);
	NODE x;
	ll lnow,rnow;
	for(i=1;i<=n;i++){
		if(i+L-1>n) break;
		lnow=i+L-1;
		rnow=min(i+R-1,n);
		x.pos=i,x.l=lnow,x.r=rnow;
		x.calc();
		Q.push(x);
	}
}
int main(){
	freopen("piano.in","r",stdin);
	freopen("piano.out","w",stdout);
	init();
	work();
	cout<<ans<<endl;
	return 0;
}