记录编号 |
60518 |
评测结果 |
AAAAAAAAAA |
题目名称 |
[NOI 2010]超级钢琴 |
最终得分 |
100 |
用户昵称 |
cstdio |
是否通过 |
通过 |
代码语言 |
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;
}