• 【题解】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;
    }
    
    
  • 相关阅读:
    spark dataframe 正则表达式匹配
    JVM申请的memory不够导致无法启动SparkContext
    <scope>provided</scope> 关于maven依赖中的scope的作用和用法
    web前端网站
    元素居中
    如何在Vue项目中使用vw实现移动端适配
    微任务、宏任务、同步、异步、Promise、Async、await
    前端自动化工作流环境
    Web前端学习笔记——构建前端自动化工作流环境
    JS判断值是否是数字
  • 原文地址:https://www.cnblogs.com/winlere/p/10380566.html
Copyright © 2020-2023  润新知