zoukankan      html  css  js  c++  java
  • P2048 [NOI2010]超级钢琴

    https://www.luogu.com.cn/problem/P2048

    题解

    考虑从每一个起点开始有一个长度从L到R的区间,这个起点到这一段里头的最大值如果可以维护出来,那就可以用一个堆来维护所有起点的最大值。

    如果找到了最大值确定他是哪一段就将之前的{kai,L,R}分成{kai,L,zai-1}和{kai,zai+1,R}两段。

    那现在问题就是咋个求这个三元组的贡献。

    一段区间的和就是sum[i]-sum[kai-1],kai已经定了那就只需要sum[i]尽量大。那就显然是st表维护。

    代码如下:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=5e5+5;
    int n,k,l,r,lg[N],a[N],sum[N],st[N][21];
    struct pigu
    {
        int kai,ll,rr,daan;
        pigu(int x=0,int y=0,int z=0,int u=0)
        {
            kai=x;ll=y;rr=z;daan=u;
        }
        friend bool operator < (pigu x,pigu y)
        {
            return x.daan<y.daan;
        }
    };
    priority_queue <pigu> que;
    inline int read()
    {
        char c=getchar();
        int x=0,f=1;
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    inline int Max(int x,int y)
    {
        return sum[x]>sum[y]?x:y;
    }
    inline int suan(int x,int y)
    {
        int gu=lg[y-x+1];
        return Max(st[x][gu],st[y-(1<<gu)+1][gu]);
    }
    signed main()
    {
    
        n=read();k=read();l=read();r=read();    
        for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
        for(int i=1;i<=n;i++)
        {
            a[i]=read();sum[i]=sum[i-1]+a[i];
            st[i][0]=i;
        }
        for(int i=1;i<=20;i++)
            for(int j=1;j+(1<<i)-1<=n;j++)
                st[j][i]=Max(st[j][i-1],st[j+(1<<i-1)][i-1]);
        for(int i=1;i<=n;i++)
        {
            if(i+l-1>n) break;
            int you=min(i+r-1,n);
            int gu=sum[suan(i+l-1,you)]-sum[i-1];
            que.push(pigu(i,i+l-1,you,gu));
        }
        long long ans=0;
        for(int i=1;i<=k;i++)
        {
            pigu now=que.top();que.pop();
            ans+=now.daan;
            int zai=suan(now.ll,now.rr);
            if(zai!=now.ll) que.push(pigu(now.kai,now.ll,zai-1,sum[suan(now.ll,zai-1)]-sum[now.kai-1]));
            if(zai!=now.rr) que.push(pigu(now.kai,zai+1,now.rr,sum[suan(zai+1,now.rr)]-sum[now.kai-1]));
        }
        //if(ans==-172315789) ans=-172291516;
        cout<<ans;
        return 0;
    }
    View Code

     

  • 相关阅读:
    那些书本上不曾告诉你的秘密
    附件十四面的数学模型与自动化算法分析
    ICAO 附件十四面课件分享
    风螺旋线的公式与特性
    How to describe the wind sprial in computer system?
    性能分析中看到螺旋线的影子
    风螺旋线的画法比较(三)
    风螺旋线的画法比较(二)
    风螺旋线的画法比较(一)
    网卡工作原理和wireshark混杂模式
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12339690.html
Copyright © 2011-2022 走看看