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

    浅谈(RMQ)https://www.cnblogs.com/AKMer/p/10128219.html

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2006

    首先,序列([l,r])的和可以转化成前缀和相减:(sum[r]-sum[l-1])

    其次,对于每个右端点(pos),有效左端点都是一段区间([pos-r,pos-l])。而这里面前缀和最小的则是最优左端点。

    一开始我们将所有的四元组((v,pos,l,r))丢到大根堆里。这个四元组表示以(pos)为右端点,有效左端点区间在([l,r])内,最大值为(v)。假设最优左端点是(pos'),那么对于最优解,我们只需要执行如下步骤(k)次即可:

    取出堆顶,(ans+=v)

    ((sum[pos]-query(l,pos'-1),pos,l,pos'-1))((sum[pos]-query(pos'+1,r),pos,pos'+1,r))放回堆里。这样可以保证([pos',pos])不会再被取出。

    (query(l,r))表示求区间([l,r])的前缀和最小值。这样,问题就得到了完美解决。

    时间复杂度:(O(nlogn))

    空间复杂度:(O(nlogn))

    代码如下:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
     
    const int maxn=5e5+5;
     
    ll ans;
    int n,limit,L,R;
    int a[maxn],Log[maxn],f[20][maxn];
     
    int read() {
        int x=0,f=1;char ch=getchar();
        for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
        for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
        return x*f;
    }
     
    struct node {
        int v,pos,l,r;
     
        node() {}
     
        node(int _v,int _pos,int _l,int _r) {
            v=_v,pos=_pos,l=_l,r=_r;
        }
     
        bool operator<(const node &a)const {
            return v<a.v;
        }
    };
     
    struct Heap {
        int tot;
        node tree[maxn<<1];
     
        void ins(node a) {
            tree[++tot]=a;
            int pos=tot;
            while(pos>1) {
                if(tree[pos>>1]<tree[pos])
                    swap(tree[pos>>1],tree[pos]),pos>>=1;
                else break;
            }
        }
     
        node pop() {
            node res=tree[1];
            tree[1]=tree[tot--];
            int pos=1,son=2;
            while(son<=tot) {
                if(son<tot&&tree[son]<tree[son|1])son|=1;
                if(tree[pos]<tree[son])
                    swap(tree[pos],tree[son]),pos=son,son=pos<<1;
                else break;
            }
            return res;
        }
    }T;//手写堆carry你进第一版,值得拥有!
     
    int fake(int num1,int num2) {
        if(a[num1]<a[num2])return num1;
        return num2;
    }
     
    int query(int l,int r) {
        int x=Log[r-l+1];
        return fake(f[x][l],f[x][r-(1<<x)+1]);
    }
     
    int main() {
        n=read(),limit=read();
        L=read(),R=read();Log[0]=-1;
        for(int i=1;i<=n;i++) {
            f[0][i]=i;
            Log[i]=Log[i>>1]+1;
            a[i]=read()+a[i-1];
        }
        for(int i=1;i<=19;i++)
            for(int j=0;j+(1<<i)-1<=n;j++)
                f[i][j]=fake(f[i-1][j],f[i-1][j+(1<<(i-1))]);
        for(int i=L;i<=n;i++) {
            int l=max(0,i-R),r=i-L;
            T.ins(node(a[i]-a[query(l,r)],i,l,r));
        }
        for(int i=1;i<=limit;i++) {
            node tmp=T.pop();
            ans+=tmp.v;
            int pos=query(tmp.l,tmp.r);
            if(pos-1>=tmp.l)
                T.ins(node(a[tmp.pos]-a[query(tmp.l,pos-1)],tmp.pos,tmp.l,pos-1));
            if(pos+1<=tmp.r)
                T.ins(node(a[tmp.pos]-a[query(pos+1,tmp.r)],tmp.pos,pos+1,tmp.r));
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Bootstrap学习笔记(2)--栅格系统深入学习
    如何用手机访问电脑上的html文件
    Jquery学习笔记(11)--jquery的ajax删除用户,非常简单!
    Jquery学习笔记(10)--ajax删除用户,使用了js原生ajax
    Jquery学习笔记(9)--注册验证复习(未用到ajax)
    CSS学习笔记(3)--表格边框
    CSS学习笔记(2)--html中checkbox和radio
    Jquery学习笔记(8)--京东导航菜单(2)增加弹框
    Jquery学习笔记(7)--京东导航菜单
    CSS学习笔记(1)--浮动
  • 原文地址:https://www.cnblogs.com/AKMer/p/10128227.html
Copyright © 2011-2022 走看看