zoukankan      html  css  js  c++  java
  • hdu 5748(求解最长上升子序列的两种O(nlogn)姿势)

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=5748


    树状数组:

    /*
    对于普通的LIS:
    for(i):1~n LIS[i]=1;
    if j<i and a[j]<a[i]
    LIS[i]=LIS[j]+1
    因此可知LIS转移需要两个条件
    1.(j<i) 序号必须在i之前
    2.(a[i]>a[j]) 值必须比a[i]小
    利用树状数组的顺序操作:{查找的都是已经出现的,序号在前(满足条件1)}
    对于每一个值,查找它在数组中的排名,再去寻找小于它的排名的最大的LIS(满足条件2)
    这里利用到了排名,因为这样可以最大限度地压缩C数组的空间
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int Max=1e5+10;
    int A[Max],V[Max],L[Max],C[Max],len;
    int lowbit(int x) {return x&(-x);}
    int Sum(int x)           //求值小于等于x的LIS的最大值
    {
        int ret=0;
        while(x>0)
        {
            if(C[x]>ret) ret=C[x];
            x-=lowbit(x);
        }
        return ret;
    }
    void Add(int x,int d)   //值大于等于x的LIS都改为LIS(x)
    {
        while(x<=len)
        {
            if(d>C[x]) C[x]=d;
            x+=lowbit(x);
        }
    }
    int main()
    {
        int T;
        for(scanf("%d",&T);T;T--)
        {
           int n;
           scanf("%d",&n);
           for(int i=1;i<=n;i++)
           {
              scanf("%d",&A[i]);
              V[i]=A[i];
           }
           sort(V+1,V+1+n);
           len=unique(V+1,V+1+n)-(V+1);
           memset(C,0,sizeof(C));
           int ans=1,tmp,xu;
           for(int i=1;i<=n;i++)
           {
               xu=lower_bound(V+1,V+1+len,A[i])-(V);
               tmp=Sum(xu-1)+1;
               L[i]=tmp;
               Add(xu,tmp);
           }
           for(int i=1;i<=n;i++)
           {
              if(i!=1) printf(" ");
              printf("%d",L[i]);
           }
           puts("");
        }
        return 0;
    }


    dp+二分

    /*
    以dp[x]代表长度为x的LIS,且dp[x]==LIS长度为x的末尾值
    每次都往前取dp[x]中最小的一个,当然在保证x尽可能地大的情况下
    因为dp[x]是递增的,所以可以二分,l=1,r=当前最长的LIS
    求得当前以小于当前a[i]的最长LIS
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int Max=1e5+10;
    int A[Max];
    int dp[Max];
    int LIS[Max];
    void Get_lis(int n)
    {
        int i,j,l,r,mid,ans;
        dp[1]=A[1];
        int len=1;
        for(i=2;i<=n;i++)
        {
            if(dp[len]<A[i]) j=++len;
            else
            {
                l=1;r=len;
                ans=0;
                while(l<=r)
                {
                    mid=(l+r)>>1;
                    if(A[i]>dp[mid]&&A[i]<=dp[mid+1])
                    {
                        ans=mid;break;
                    }
                    else if(A[i]>dp[mid]) l=mid+1;
                    else r=mid-1;
                }
                j=ans+1;
            }
            dp[j]=A[i];
            LIS[i]=j;
        }
    }
    int main()
    {
        int T;
        for(scanf("%d",&T);T;T--)
        {
            int n;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&A[i]);
                dp[i]=0;
            }
            LIS[1]=1;
            Get_lis(n);
            for(int i=1;i<=n;i++)
            {
                if(i!=1) printf(" ");
                printf("%d",LIS[i]);
            }
            puts("");
        }
        return 0;
    }


    其实还有一种单调队列求最长上升子序列的方法,可是不能用来解这道题

    /*
    无解。。。
    单调队列只能求出总体的LIS长度
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int Max=1e5+10;
    int que[Max];
    int main()
    {
        int T;
        for(scanf("%d",&T);T;T--)
        {
            int n,x,top=0;
            scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                scanf("%d",&x);
                if(x>que[top]||top==0)
                {
                    que[++top]=x;
                }
                else
                {
                    int l=1,r=top,mid,ans;
                    ans=0;
                    while(l<=r)
                    {
                        mid=l+(r-l)/2;
                        if(que[mid]<x) l=mid+1;
                        else r=mid-1,ans=mid;
                    }
                    que[ans]=x;
                }
            }
            cout<<top<<endl;
        }
        return 0;
    }
  • 相关阅读:
    property 中的strong 与weak
    ios5 StoryBoard
    PLINQ中的分区
    ZOJ3704 I am Nexus Master! 模拟
    POJ1470 Closest Common Ancestors TarjanLCA
    XTU1170 Coin 线段树
    HDU2586 How far away ? LCATarjan Or spfa
    CF#303C Minimum Modular 数学分析
    CF#303B Rectangle Puzzle II 数学分析
    ZOJ3698 Carrot Fantasy 恶心模拟
  • 原文地址:https://www.cnblogs.com/zsyacm666666/p/5703745.html
Copyright © 2011-2022 走看看