• BZOJ3594 SCOI2014方伯伯的玉米田(动态规划+树状数组)


      可以发现每次都对后缀+1是不会劣的。考虑dp:设f[i][j]为前i个数一共+1了j次时包含第i个数的LIS长度。则f[i][j]=max(f[i][j-1],f[k][l]+1) (k<i,l<=j,a[i]+j>=a[k]+l)。容易发现这里是二维偏序,相当于查询(j,a[i]+j)左下部分的最大值,二维树状数组暴力维护,复杂度O(nklogklogv)。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 10010
    #define M 510
    #define V 5010 
    int n,m,a[N],f[N][M];
    int tree[M][V+M];
    void ins(int x,int y,int k)
    {
        for (;x<=m+1;x+=x&-x)
            for (int i=y;i<=5500;i+=i&-i)
            tree[x][i]=max(tree[x][i],k);
    }
    int query(int x,int y)
    {
        int s=0;
        for (;x;x-=x&-x)
            for (int i=y;i;i-=i&-i)
            s=max(s,tree[x][i]);
        return s;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj3594.in","r",stdin);
        freopen("bzoj3594.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        int t=0;
        for (int i=1;i<=n;i++) a[i]=read();
        for (int i=1;i<=n;i++)
        {
            for (int j=0;j<=m;j++)
            {
                if (j) f[i][j]=f[i][j-1];
                f[i][j]=max(f[i][j],query(j+1,a[i]+j)+1);
            }
            for (int j=0;j<=m;j++)
            ins(j+1,a[i]+j,f[i][j]);
        }
        for (int i=1;i<=n;i++) f[0][m]=max(f[0][m],f[i][m]);
        cout<<f[0][m];
        return 0;
    }
    View Code

      虽然看到题解清一色的都是二维BIT,仔细琢磨一下还是感觉自己原来的维护方法并没有假。容易发现f[i][j]>=f[i][j-1],那么k确定时l取值越大越好,所以两个限制至少有一个取等号。那么可以改为维护很多棵BIT,复杂度变为O(nk(logk+logv))。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 10010
    #define M 510
    #define V 5010 
    int n,m,a[N],f[N][M];
    int tree1[M][V+M],tree2[V+M][M];
    void ins1(int x,int k,int p){while (k<=5500) tree1[x][k]=max(tree1[x][k],p),k+=k&-k;}
    void ins2(int x,int k,int p){while (k<=501) tree2[x][k]=max(tree2[x][k],p),k+=k&-k;}
    int query1(int x,int k){int s=0;while (k) s=max(s,tree1[x][k]),k-=k&-k;return s;}
    int query2(int x,int k){int s=0;while (k) s=max(s,tree2[x][k]),k-=k&-k;return s;}
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj3594.in","r",stdin);
        freopen("bzoj3594.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        int t=0;
        for (int i=1;i<=n;i++) a[i]=read();
        for (int i=1;i<=n;i++)
        {
            for (int j=0;j<=m;j++)
            {
                if (j) f[i][j]=f[i][j-1];
                f[i][j]=max(f[i][j],max(query1(j,a[i]+j),query2(a[i]+j,j+1))+1);
            }
            for (int j=0;j<=m;j++)
            ins1(j,a[i]+j,f[i][j]),ins2(a[i]+j,j+1,f[i][j]);
        }
        for (int i=1;i<=n;i++) f[0][m]=max(f[0][m],f[i][m]);
        cout<<f[0][m];
        return 0;
    }
  • 相关阅读:
    java/jsp执行sql语句的方式
    Java 编辑html模板并生成pdf
    Kubernetes的主要功能
    AJPFX浅谈Java性能优化之finalize 函数
    AJPFX浅谈Java 性能优化之垃圾回收(GC)
    AJPFX浅谈Java 性能优化之字符串过滤实战
    AJPFX谈Java 性能优化之基本类型 vs 引用类型
    AJPFX谈JAVA新手问题之异常处理使用不当
    AJPFX浅谈Java新手问题之缺少良好的编程习惯
    AJPFX浅谈关于Java程序员缺乏面向对象的基本功的问题
  • 原文地址:https://www.cnblogs.com/Gloid/p/9709086.html
Copyright © 2020-2023  润新知