zoukankan      html  css  js  c++  java
  • 【题解】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;
    }
    
    
  • 相关阅读:
    Single Number II
    Pascal's Triangle
    Remove Duplicates from Sorted Array
    Populating Next Right Pointers in Each Node
    Minimum Depth of Binary Tree
    Unique Paths
    Sort Colors
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Climbing Stairs
  • 原文地址:https://www.cnblogs.com/winlere/p/10380566.html
Copyright © 2011-2022 走看看