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

树状数组:

  1. /*
  2. 对于普通的LIS:
  3. for(i):1~n LIS[i]=1;
  4. if j<i and a[j]<a[i]
  5. LIS[i]=LIS[j]+1
  6. 因此可知LIS转移需要两个条件
  7. 1.(j<i) 序号必须在i之前
  8. 2.(a[i]>a[j]) 值必须比a[i]小
  9. 利用树状数组的顺序操作:{查找的都是已经出现的,序号在前(满足条件1)}
  10. 对于每一个值,查找它在数组中的排名,再去寻找小于它的排名的最大的LIS(满足条件2)
  11. 这里利用到了排名,因为这样可以最大限度地压缩C数组的空间
  12. */
  13. #include <bits/stdc++.h>
  14. using namespace std;
  15. const int Max=1e5+;
  16. int A[Max],V[Max],L[Max],C[Max],len;
  17. int lowbit(int x) {return x&(-x);}
  18. int Sum(int x) //求值小于等于x的LIS的最大值
  19. {
  20. int ret=;
  21. while(x>)
  22. {
  23. if(C[x]>ret) ret=C[x];
  24. x-=lowbit(x);
  25. }
  26. return ret;
  27. }
  28. void Add(int x,int d) //值大于等于x的LIS都改为LIS(x)
  29. {
  30. while(x<=len)
  31. {
  32. if(d>C[x]) C[x]=d;
  33. x+=lowbit(x);
  34. }
  35. }
  36. int main()
  37. {
  38. int T;
  39. for(scanf("%d",&T);T;T--)
  40. {
  41. int n;
  42. scanf("%d",&n);
  43. for(int i=;i<=n;i++)
  44. {
  45. scanf("%d",&A[i]);
  46. V[i]=A[i];
  47. }
  48. sort(V+,V++n);
  49. len=unique(V+,V++n)-(V+);
  50. memset(C,,sizeof(C));
  51. int ans=,tmp,xu;
  52. for(int i=;i<=n;i++)
  53. {
  54. xu=lower_bound(V+,V++len,A[i])-(V);
  55. tmp=Sum(xu-)+;
  56. L[i]=tmp;
  57. Add(xu,tmp);
  58. }
  59. for(int i=;i<=n;i++)
  60. {
  61. if(i!=) printf(" ");
  62. printf("%d",L[i]);
  63. }
  64. puts("");
  65. }
  66. return ;
  67. }

dp+二分

  1. /*
  2. 以dp[x]代表长度为x的LIS,且dp[x]==LIS长度为x的末尾值
  3. 每次都往前取dp[x]中最小的一个,当然在保证x尽可能地大的情况下
  4. 因为dp[x]是递增的,所以可以二分,l=1,r=当前最长的LIS
  5. 求得当前以小于当前a[i]的最长LIS
  6. */
  7. #include <bits/stdc++.h>
  8. using namespace std;
  9. const int Max=1e5+;
  10. int A[Max];
  11. int dp[Max];
  12. int LIS[Max];
  13. void Get_lis(int n)
  14. {
  15. int i,j,l,r,mid,ans;
  16. dp[]=A[];
  17. int len=;
  18. for(i=;i<=n;i++)
  19. {
  20. if(dp[len]<A[i]) j=++len;
  21. else
  22. {
  23. l=;r=len;
  24. ans=;
  25. while(l<=r)
  26. {
  27. mid=(l+r)>>;
  28. if(A[i]>dp[mid]&&A[i]<=dp[mid+])
  29. {
  30. ans=mid;break;
  31. }
  32. else if(A[i]>dp[mid]) l=mid+;
  33. else r=mid-;
  34. }
  35. j=ans+;
  36. }
  37. dp[j]=A[i];
  38. LIS[i]=j;
  39. }
  40. }
  41. int main()
  42. {
  43. int T;
  44. for(scanf("%d",&T);T;T--)
  45. {
  46. int n;
  47. scanf("%d",&n);
  48. for(int i=;i<=n;i++)
  49. {
  50. scanf("%d",&A[i]);
  51. dp[i]=;
  52. }
  53. LIS[]=;
  54. Get_lis(n);
  55. for(int i=;i<=n;i++)
  56. {
  57. if(i!=) printf(" ");
  58. printf("%d",LIS[i]);
  59. }
  60. puts("");
  61. }
  62. return ;
  63. }

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

  1. /*
  2. 无解。。。
  3. 单调队列只能求出总体的LIS长度
  4. */
  5. #include <bits/stdc++.h>
  6. using namespace std;
  7. const int Max=1e5+;
  8. int que[Max];
  9. int main()
  10. {
  11. int T;
  12. for(scanf("%d",&T);T;T--)
  13. {
  14. int n,x,top=;
  15. scanf("%d",&n);
  16. for(int i=;i<n;i++)
  17. {
  18. scanf("%d",&x);
  19. if(x>que[top]||top==)
  20. {
  21. que[++top]=x;
  22. }
  23. else
  24. {
  25. int l=,r=top,mid,ans;
  26. ans=;
  27. while(l<=r)
  28. {
  29. mid=l+(r-l)/;
  30. if(que[mid]<x) l=mid+;
  31. else r=mid-,ans=mid;
  32. }
  33. que[ans]=x;
  34. }
  35. }
  36. cout<<top<<endl;
  37. }
  38. return ;
  39. }

hdu 5748(求解最长上升子序列的两种O(nlogn)姿势)的更多相关文章

  1. 求解最长递增子序列(LIS) | 动态规划(DP)+ 二分法

    1.题目描述     给定数组arr,返回arr的最长递增子序列. 2.举例     arr={2,1,5,3,6,4,8,9,7},返回的最长递增子序列为{1,3,4,8,9}. 3.解答      ...

  2. HDU 4681 String 最长公共子序列

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4681 题意: 给你a,b,c三个串,构造一个d串使得d是a,b的子序列,并且c是d的连续子串.求d最大 ...

  3. hdu 1025 dp 最长上升子序列

    //Accepted 4372 KB 140 ms //dp 最长上升子序列 nlogn #include <cstdio> #include <cstring> #inclu ...

  4. hdu 5489(LIS最长上升子序列)

    题意:一个含有n个元素的数组,删去k个连续数后,最长上升子序列        /*思路参考GoZy 思路: 4 2 3 [5 7 8] 9 11 ,括号表示要删掉的数, 所以  最长上升子序列  = ...

  5. hdu 5532(最长上升子序列)

    Input The first line contains an integer T indicating the total number of test cases. Each test case ...

  6. Python动态规划求解最长递增子序列(LIS)

    原始代码错误,移步博客查看O(N^2)及优化的O(N*logN)的实现:每天一道编程题--最长递增子序列

  7. 算法练习--- DP 求解最长上升子序列(LIS)

    问题描写叙述: 对于2,5,3,1,9,4,6,8,7,找出最长上升子序列的个数 最长上升子序列定义: 对于i<j i,j∈a[0...n] 满足a[i]<a[j] 1. 找出DP公式:d ...

  8. HDU 1159.Common Subsequence-最长公共子序列(LCS)

    Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  9. 最长上升子序列算法(n^2 及 nlogn) (LIS) POJ2533Longest Ordered Subsequence

    问题描述: 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的.对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列 ...

随机推荐

  1. tp框架 中的时间 查询范围

    $where['add_time'] = array(array('egt',$starttime),array('elt',$endtime),'AND');

  2. Python自动化 【第六篇】:Python基础-面向对象

      目录: 面向过程VS面向对象 面向对象编程介绍 为什么要用面向对象进行开发 面向对象的特性:封装.继承.多态 面向过程 VS 面向对象 面向过程编程(Procedural Programming) ...

  3. 34、Shiro框架入门三,角色管理

    //首先这里是java代码,就是根据shiro-role.ini配置文件中的信息来得到role与用户信息的对应关系//从而来管理rolepublic class TestShiroRoleTest e ...

  4. 进阶篇:以IL为剑,直指async/await

    接上篇:30分钟?不需要,轻松读懂IL,这篇主要从IL入手来理解async/await的工作原理. 先简单介绍下async/await,这是.net 4.5引入的语法糖,配合Task使用可以非常优雅的 ...

  5. Linux_09------Linux上系统扫描和安全策略

    先谢慕课网/** * linux系统扫描技术 * * 主机扫描.路由扫描.批量服务扫描.系统安全策略(防SYN和ddos攻击) */ /** * 主机扫描 * ping fping hping * * ...

  6. UART IP和UVM的验证平台

    UART是工程师在开发调试时最常用的工具的,其通信协议简单.opencores 网站提供了兼容16550a的UART IP其基本特性如下: uart16550 is a 16550 compatibl ...

  7. Add Binary <leetcode>

    Given two binary strings, return their sum (also a binary string). For example,a = "11"b = ...

  8. VS2008中调试dll

    1.运行dll实例时,会直接弹出一个小框: 选择可拉起这个dll的exe运行就可以调试了 2.以后每次都会直接运行了,要重新选择程序,弹出上面的框,需要在project-->debugging- ...

  9. proc文件系统在内核中的表现

    当Linux内核启动起来之后,我们可以通过proc虚拟文件系统来查看内的中的一些动态信息. 例如:可以 cat  /proc/misc  来查看系统中装载的所有misc类设备 cat  /proc/d ...

  10. Linux(centos)系统各个目录的作用详解

    Linux(centos)系统各个目录的作用详解 文件系统的类型 LINUX有四种基本文件系统类型:普通文件.目录文件.连接文件和特殊文件,可用file命令来识别. 普通文件:如文本文件.C语言元代码 ...