zoukankan      html  css  js  c++  java
  • 【NOI2010】超级钢琴

    题目链接

    设$s_i=sumlimits_{j=1}^i a_j$,那么相同左端点$l$的区间之中,最大的区间和就是$mathop{max}limits_{i=l+L-1}^{i+R-1}{s_i-s_{l-1}}=mathop{max}limits_i{s_i}-s_{l-1}$。

    那对前缀和做ST表就可以快速求解了。

    设$f(i,l,r,t)$表示左端点是$i$,右端点在$[l,r]$范围内,使区间和最大的区间右端点是$t$,的最大区间和。

    那我们可以把所有的$f(i,i+L-1,i+R-1,t)$丢进堆里,取$k$次,每次把右端点区间按$(l,t-1)$和$(t+1,r)$分开重新压进堆里。

    代码(100分):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    #define IL inline
    #define RG register
    #define _1 first
    #define _2 second
    using namespace std;
    typedef long long LL;
    const int N=5e5;
    const int L=18;
    
        int n,k,llim,rlim;
        LL a[N+3],s[N+3];
        
        int lg2[N+3];
        int f[N+3][L+3];
        
    IL void init(){
        s[0]=0;
        for(int i=1;i<=n;i++)
            s[i]=s[i-1]+a[i];
        
        lg2[0]=lg2[1]=0;
        for(int i=2;i<=n;i++)
        if((1<<(lg2[i-1]+1))==i)
            lg2[i]=lg2[i-1]+1;
        else 
            lg2[i]=lg2[i-1];
        
        for(int i=1;i<=n;i++)
            f[i][0]=i;
        for(int l=1;l<=lg2[n];l++)
            for(int i=1;i<=n;i++){
                int j=i+(1<<(l-1));
                if(j>n||s[f[i][l-1]]>s[f[j][l-1]])
                    f[i][l]=f[i][l-1];
                else 
                    f[i][l]=f[j][l-1];
                
            }
        
    }
    
    IL int qry(int l,int r){
        int len=r-l+1,k=lg2[len],t=l+len-(1<<k);
        return (s[f[l][k]]>s[f[t][k]])?f[l][k]:f[t][k];
    }
    
    struct Dat{
        int i,l,r,k;    Dat(){}
        Dat(int i,int l,int r,int k)
            :i(i),l(l),r(r),k(k){}
    };
    
    IL bool operator<(Dat x,Dat y){    //warning: i differ
        return s[x.k]-s[x.i-1]<s[y.k]-s[y.i-1];
    }
    
        priority_queue<Dat>hp;
    
    int main(){
        scanf("%d%d%d%d",&n,&k,&llim,&rlim);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        
        init();
        
        for(int i=1;i+llim-1<=n;i++){
            int l=i+llim-1,r=min(i+rlim-1,n);
            hp.push(Dat(i,l,r,qry(l,r)));
            
        }
        LL ans=0;
        while(k--){
            Dat x=hp.top();    hp.pop();
            ans+=s[x.k]-s[x.i-1];
            
            if(x.l<x.k)
                hp.push(Dat(x.i,x.l,x.k-1,qry(x.l,x.k-1)));
            if(x.k<x.r)
                hp.push(Dat(x.i,x.k+1,x.r,qry(x.k+1,x.r)));
            
        }
        
        printf("%lld",ans);
    
        return 0;
    
    }
    View Code
  • 相关阅读:
    [leetcode-604-Design Compressed String Iterator]
    [leetcode-617-Merge Two Binary Trees]
    OpenCV学习1-----打开摄像头并在画面上添加水印
    cvCvtColor与cvtColor区别
    [leetcode-547-Friend Circles]
    [leetcode-260-Single Number III]
    复位电路
    单片机特殊功能寄存器
    单片机的定时器与计数器
    单片机定时/计数工作方式
  • 原文地址:https://www.cnblogs.com/Hansue/p/12935102.html
Copyright © 2011-2022 走看看