zoukankan      html  css  js  c++  java
  • Sequence(ST表)(洛谷P2048)

    超级钢琴

    知识储备

    在做这道题前,我们先要了解一下ST表(一种离线求区间最值的方法)

    ST表使用DP实现的,其查询复杂度为O(1).

    那么我们怎么用DP实现呢??

    首先,我们设立一个状态f[i][j],其中i代表起点(包括在内),而j则代表是2的几次方,那么这个状态的含义就是以i为起点,求i~i+2^j-1内的区间最大值

    最开始,我们定义f[i][0]的值为其本身即a[i]

    那么我们转移方程就是

    f[i][j]=max(f[i][j-1],f[i+(1<<(j-1)][j-1]);  //一层一层的推过来...

    然后我们就知道在一定区间内的最大值了!!

    查询也是一个需要特别注意的点,我们要知道查询的x位置和y位置之间max,就要知道y-x+1是y的几次方,其中这个要向下取整,防止越界,但是这样我们就会有一部分扫不到,由于我们向下取整的这个区间是大于等于这个区间的一半的,所以我们可以反过来,从y-(1<<k)到y,这样可以保证不会漏掉数据,并且重复的话也不会对答案产生影响

    但是注意!!算k的式子要小心啊

    别取错了,一个小BUG就会导致你WA掉...

    #include<bits/stdc++.h>
    #define ll long long
    #define FOR(i,a,b) for(register int i=a;i<=b;i++)
    #define ROF(i,a,b) for(register int i=a;i>=b;i--)
    using namespace std;
    const int N=500000+10;
    int n,m;
    int a[N];
    int f[N][30];
    int scan()
    {
        int as=0,f=1;
        char c=getchar();
        while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
        while(c>='0'&&c<='9'){as=(as<<3)+(as<<1)+c-'0';c=getchar();}
        return as*f;
    }
    void RMQ(int n)
    {
        FOR(i,1,20)
        {
            FOR(j,1,n)
            {
                if(j+(1<<i)-1<=n)
                f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]);
            }
        }
    }
    int main()
    {
        n=scan();
        m=scan();
        FOR(i,1,n)
            a[i]=scan(),f[i][0]=a[i];
        RMQ(n);
        FOR(i,1,m)
        {
            int x,y;
            x=scan();
            y=scan();
            int k=(int)(log((double)(y-x+1))/log(2.0));
            printf("%d
    ",max(f[x][k],f[y-(1<<k)+1][k]));
        }
        return 0;
    }
    代码戳这里

    接下来我们要讲正事了!!

    我们的目光转到钢琴这一题上

    思路

    首先,我们前缀和储存值,然后在用KMQ,将一些区间内的max求出来

    然后我们根据题目要求,由于题目要我们求最大权值,那么我们就求每个可能区间里面的max,将其储存在堆里面.

    但是最开始的时候,我们只求出了以某一点为起点的最大值,但是我们最后要求的1~k个最大值的相加

    所以我们在每取出一个max是,再去寻找以该点为起点的max,只不过此时的max不是当前的最有解,而是次优解,但是也可能成为新的最有解,

    然后题目打这里就差不多啦

    #include<bits/stdc++.h>
    #define ll long long
    #define gc getchar()
    #define FOR(i,a,b) for(register int i=a;i<=b;i++)
    #define ROF(i,a,b) for(register int i=a;i>=b;i--)
    using namespace std;
    const int N=500000+10;
    int n,m,L,R;
    ll sum[N];
    int id[N][30],f[N][30];
    ll ans=0;
    int scan()
    {
        int as=0,f=1;char c=gc;
        while(c>'9'||c<'0'){if(c=='-') f=-1;c=gc;}
        while(c>='0'&&c<='9'){as=(as<<3)+(as<<1)+c-'0';c=gc;}
        return as*f;
    }
    //learn new
    struct s1
    {
        int u,l,r,pos;
        bool operator <(s1 y) const
        {
            return sum[pos]-sum[u-1]<sum[y.pos]-sum[y.u-1];//大的放队尾
        }
    }tmp;
    priority_queue<s1>q;//队列
    void init(int &pos,int l,int r)
    {
        int j=log2(r-l+1);
        if(f[l][j]>f[r-(1<<j)+1][j]) pos=id[l][j];
        else pos=id[r-(1<<j)+1][j];
    }//这里都懂吧,KMQ的查询
    int main()
    {
        n=scan();m=scan();L=scan();R=scan();
        FOR(i,1,n)
        {
            sum[i]=scan();sum[i]+=sum[i-1];//前缀和
            f[i][0]=sum[i];
            id[i][0]=i;//位置的处理
        }
        FOR(j,1,20)
        {
            FOR(i,1,n)
            {
                if(i+(1<<j)-1>n) break;
                if(f[i][j-1]>f[i+(1<<(j-1))][j-1]) f[i][j]=f[i][j-1],id[i][j]=id[i][j-1];
                else f[i][j]=f[i+(1<<(j-1))][j-1],id[i][j]=id[i+(1<<(j-1))][j-1];
            }//这里其实就是KMQQAQ
        }
        FOR(i,1,n-L+1)//入坑silasila......
        {
            int l=i+L-1; int r=min(i+R-1,n),pos=0,u=i;//随便给pos一个值
            init(pos,l,r);//pos在这里赋好了值
            tmp=(s1){u,l,r,pos};//然后加入四元组吧..
            q.push(tmp);//入队
        }
        while(m--)
        {
            tmp=q.top(); q.pop();//弹出顶端,即最优解
            int u=tmp.u,l=tmp.l,r=tmp.r,tps=tmp.pos,pos=tmp.pos;//去寻找次
    //优解
            ans+=sum[tps]-sum[u-1];
            if(tps>l)
            {
                init(pos,l,tps-1);tmp=(s1){u,l,tps-1,pos};q.push(tmp);
            }
            if(tps<r)
            {
                init(pos,tps+1,r);tmp=(s1){u,tps+1,r,pos};q.push(tmp);
            }
        }
        printf("%lld",ans);
        return 0;
    }
    代码戳这里
  • 相关阅读:
    nodeType 节点简介
    Hamming Codes
    Preface Numbering(还没好好看USACO的解答)
    位运算常见应用即ACM题优化实例
    Dynamic Programming(动态规划)
    operator new & new operator
    资料记录
    Ordered Fractions
    Healthy Holsteins
    Sorting A ThreeValued Sequence
  • 原文地址:https://www.cnblogs.com/KSTT/p/10380545.html
Copyright © 2011-2022 走看看