• [BZOJ 2006] 超级钢琴


    Link:

    https://www.lydsy.com/JudgeOnline/problem.php?id=2006 

    Algorithm:

    对于此类区间最值类问题,我们可以通过控制一端不变来寻找当前点的最值,再综合比较

    此题中,在求完前缀和后,在左端点确定的情况下,只要寻找前缀和最大的右端点

    为了快速寻找最优的右端点位置,我们需要RMQ来进行维护

    由于不存在修改操作而只有查询,那么ST List  O(1)查询 O(n)修改  的特性就能充分利用

    在求出前缀和后用ST list维护区间MAX即可

    定义一个四元组(i,L,R,pos),其中,i表示固定下的左端点,L,R表示右端点存在的区间,pos表示右端点此时最优位置

    为了不涉及到ST list不支持的删除操作,在选定pos后四元组分为两段:

    $(i,L,R,pos)−>(i,L,pos−1,pos′)+(i,pos+1,R,pos′′)$

    这样用优先队列每次取出最优解即可

    Code:

    //by NewErA
    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    
    inline int read()
    {
        char ch;int num,f=0;
        while(!isdigit(ch=getchar())) f|=(ch=='-');
        num=ch-'0';
        while(isdigit(ch=getchar())) num=num*10+ch-'0';
        return f?-num:num;
    }
    
    struct SP
    {
        int i,l,r,pos;
    };
    
    const int MAXN=500005;
    int n,k,L,R,a[MAXN],log_2[MAXN],st[MAXN][100];
    ll res=0;
    
    void init()
    {
        log_2[1]=0;
        for(int i=2;i<=n;i++)
        {
            log_2[i]=log_2[i-1];
            if(1<<(log_2[i]+1)==i) log_2[i]++;
        }
        
        for(int i=n;i>=1;i--)
        {
            st[i][0]=i;
            for(int j=1;(i+(1<<j)-1)<=n;j++)
                if(a[st[i][j-1]]>a[st[i+(1<<(j-1))][j-1]]) st[i][j]=st[i][j-1];
                else st[i][j]=st[i+(1<<(j-1))][j-1];
        }
    }
    
    int Query(int l,int r)
    {
        int x=log_2[r-l+1];
        if(a[st[l][x]]>a[st[r-(1<<x)+1][x]]) return st[l][x];
        else return st[r-(1<<x)+1][x];
    }
    
    inline bool operator < (SP x,SP y)  //运算符重载
    {
        return a[x.pos]-a[x.i-1]<a[y.pos]-a[y.i-1];
    } 
    
    int main()
    {
        n=read();k=read();L=read();R=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=2;i<=n;i++) a[i]+=a[i-1];
        
        init();
        
        priority_queue<SP,vector<SP> > Q;
        for(int i=1;i<=n;i++)
            if(i+L-1<=n)
            {
                int t=min(i+R-1,n);
                Q.push(SP{i,i+L-1,t,Query(i+L-1,t)});
            }
        while(k--)
        {
            SP cur=Q.top();Q.pop();
            res+=a[cur.pos]-a[cur.i-1];
            if(cur.pos-1>=cur.l) Q.push(SP{cur.i,cur.l,cur.pos-1,Query(cur.l,cur.pos-1)});
            if(cur.pos+1<=cur.r) Q.push(SP{cur.i,cur.pos+1,cur.r,Query(cur.pos+1,cur.r)});
        }
        cout << res;
        return 0;
    }

    1、priority_queue的运算符重载问题(Updating)

    2、只需要RMQ的查询操作时尽量用ST List

    3、如果删除1个或少量数据的操作难以实现时,考虑将原数据分段,递归式地考虑每一段的情况

  • 相关阅读:
    转 [ javascript面向对象技术
    制作双击可运行的jar
    使用eclipse和maven一步一步配置web项目
    [转]hibernate三种状态详解
    [转]hibernate缓存机制所有详解
    Miniprofiler在普通net项目中的使用
    sql server 中更改默认实例
    使用awstats分析iis站点的日志
    NaN 和 Infinity
    反射的结果中排除隐藏的成员
  • 原文地址:https://www.cnblogs.com/newera/p/9055600.html
Copyright © 2020-2023  润新知