【题解】P2048 [NOI2010]超级钢琴

【题解】[P2048 NOI2010]超级钢琴

一道非常套路的题目。是堆的套路题。

考虑前缀和,我们要是确定了左端点,就只需要在右端区间查询最大的那个加进来就好了。\(sum_j-sum_{i-1}​\)嘛,我们预处理对于\(sum​\)\(st​\)表,然后枚举\(i​\),然后记五元组\(sum,i,l,pos,r​\)分别表示这个五元组的\(sum_{pos}-sum_{i-1}​\)贡献,左端点\(i​\),右边范围\(l,r​\),和上次使用的下标\(pos​\)

先把所有的\((sum,i,i+L-1,maxpos,i+R-1)​\)压入大根堆,按照\(sum​\)排序

取出队头后,将五元组拆为\((sum',i,i+L-1,maxpos',maxpos-1)\)\((sum'',i,maxpos+1,maxpos'',i+R-1)\)再放入堆里。

上面五元组的拆分只是意会,在代码中有些小细节不一样,不一定是\(i+L-1\),\(i+R-1\)

这样连续操作\(k\)次,他们的和就是我们要的答案。

#include<bits/stdc++.h>

using namespace std;typedef long long ll;
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;--t)
#define RP(t,a,b)  for(register int t=(a),edd=(b);t<=edd;++t)
#define ERP(t,a)   for(register int t=head[a];t;t=e[t].nx)
#define midd register int mid=(l+r)>>1
#define TMP template < class ccf >
TMP inline ccf qr(ccf b){
    register char c=getchar();register int q=1;register ccf x=0;
    while(c<48||c>57)q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)x=x*10+c-48,c=getchar();
    return q==-1?-x:x;}
TMP inline ccf Max(ccf a,ccf b){return a<b?b:a;}
TMP inline ccf Min(ccf a,ccf b){return a<b?a:b;}
TMP inline ccf Max(ccf a,ccf b,ccf c){return Max(a,Max(b,c));}
TMP inline ccf Min(ccf a,ccf b,ccf c){return Min(a,Min(b,c));}
TMP inline void READ(ccf* _arr,int _n){RP(t,1,_n)_arr[t]=qr((ccf)1)+_arr[t-1];}
TMP inline void Swap(ccf a,ccf b){ccf c;c=b;b=a;a=c;}
//----------------------template&IO---------------------------
#define int long long
const int maxn=500005;
int data[maxn];
int lg[maxn];
struct ST{
    int sum,id;
    inline bool operator <(ST a)const{return sum==a.sum?id<a.id:sum<a.sum;}
}st[maxn][32];
int n,lb,rb,k;
inline int qint(int l,int r){return Max(st[l][lg[r-l+1]],st[r-(1<<lg[r-l+1])+1][lg[r-l+1]]).sum;}
inline int qpos(int l,int r){return Max(st[l][lg[r-l+1]],st[r-(1<<lg[r-l+1])+1][lg[r-l+1]]).id ;}
struct node{
    int sum,i,L,pos,R;
    inline bool operator < (node a)const{return sum==a.sum?pos<a.pos:sum<a.sum;}
};
priority_queue < node > q;

inline node mk(int sum,int i,int L,int pos,int R){node ret=(node){sum,i,L,pos,R};return ret;}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("sequence1.in","r",stdin);
    freopen("sequence.out","w",stdout);
#endif
    n=qr(1);k=qr(1);lb=qr(1);rb=qr(1);
    READ(data,n);
    const int* sum=data;
    RP(t,1,n+1){
	lg[t]=lg[t-1];
	if((1<<lg[t]<<1)==t)lg[t]++;

    }
    int ans=0;
    int L=lb,R=rb;
    RP(t,1,n) st[t][0].sum=data[t],st[t][0].id=t;
    DRP(t,n,1){
	st[t][0].sum=data[t];st[t][0].id=t;
	RP(i,1,lg[n-t+1]) st[t][i]=Max(st[t][i-1],st[t+(1<<(i-1))][i-1]);
    }
    RP(t,1,n){
	if(t+R-1<=n)      q.push(mk(qint(t+L-1,t+R-1)-sum[t-1],t,t+L-1,qpos(t+L-1,t+R-1),t+R-1));
	else if(t+L-1<=n) q.push(mk(qint(t+L-1,n)    -sum[t-1],t,t+L-1,qpos(t+L-1,n)    ,n    ));
    }
    RP(qaqqqq,1,k){
	register node now=q.top();q.pop();
	ans+=now.sum;
	if(now.pos>now.L&&now.pos<=now.R) q.push(mk(qint(now.L,now.pos-1)-sum[now.i-1],now.i,now.L,qpos(now.L,now.pos-1),now.pos-1));
	if(now.pos<now.R&&now.pos>=now.L) q.push(mk(qint(now.pos+1,now.R)-sum[now.i-1],now.i,now.pos+1,qpos(now.pos+1,now.R),now.R));
    }
    cout<<ans<<endl;
    return 0;
}

posted @ 2019-02-14 20:31  谁是鸽王  阅读(217)  评论(0编辑  收藏  举报