POJ 1631 Bridging signals DP(最长上升子序列)
2016-05-04 09:27
375 查看
最近一直在做《挑战程序设计竞赛》的练习题,感觉好多经典的题,都值得记录。
题意:给你t组数据,每组数组有n个数字,求每组的最长上升子序列的长度。
思路:由于n最大为40000,所以n*n的复杂度不够了,会超时。
书上状态方程换成了d[i]——以长度为i+1的上升子序列中末尾元素的最小值。
那么我们在遍历第i个元素时候,以这个元素为末尾元素的最长子序列也就是在d[i]中找到一个小于num[i]的最大值,然后在这个序列末尾加上num[i]
显然,我们在查找时便可以利用二分搜索,从而把复杂度从原来的n变为了logn,总复杂度从n*n变成了nlogn
d[i]已经保证了长度为i+1的上升子序列末尾元素的最小值,那么对于d[i+1]长度为i+2的子序列里面,要获得最长,自然就要从长度为i+1的子序列中,挑选末尾元素为最小的子序列后面添加元素。所以d[i+1] > d[i],d数组是一个递增的数组,所以就能用二分搜索了。
AC代码:
题意:给你t组数据,每组数组有n个数字,求每组的最长上升子序列的长度。
思路:由于n最大为40000,所以n*n的复杂度不够了,会超时。
书上状态方程换成了d[i]——以长度为i+1的上升子序列中末尾元素的最小值。
那么我们在遍历第i个元素时候,以这个元素为末尾元素的最长子序列也就是在d[i]中找到一个小于num[i]的最大值,然后在这个序列末尾加上num[i]
显然,我们在查找时便可以利用二分搜索,从而把复杂度从原来的n变为了logn,总复杂度从n*n变成了nlogn
d[i]已经保证了长度为i+1的上升子序列末尾元素的最小值,那么对于d[i+1]长度为i+2的子序列里面,要获得最长,自然就要从长度为i+1的子序列中,挑选末尾元素为最小的子序列后面添加元素。所以d[i+1] > d[i],d数组是一个递增的数组,所以就能用二分搜索了。
lower_bound(d,d+n,num[i]); //默认数组d为上升数组,返回第一个大于等于num[i]的指针。
lower_bound(d,d+n,num[i],greater<int>()); //表达数组d为下降数组,返回第一个小于等于num[i]的指针。
AC代码:
#include <cstdio> #include <algorithm> #include <iostream> using namespace std; const int N = 40005; const int INF = 0X3F3F3F3F; int n,t,num ,d ; //d[i] = 长度为i+1的上升子序列中末尾元素的最小值,不存在则INF void solve() { for(int i = 0; i < n; i++) d[i] = INF; for(int i = 0; i < n; i++) { scanf("%d", num+i); *lower_bound(d,d+n,num[i]) = num[i]; } printf("%d\n", lower_bound(d,d+n,INF) - d); } int main() { scanf("%d", &t); while(t--) { scanf("%d", &n); solve(); } return 0; }
相关文章推荐
- Linux磁盘扩容LVM
- IntelliJ IDEA激活
- Markdown与Bootstrap相结合实现图片自适应属性
- Win8.1系统程序运行发生冲突提示"APPCRASH”错误的故障原因及解决方法
- java如何获取SQL查询结果集中的行数和列数
- recv()和send()函数
- Java 正则表达式详解
- juce中的CallbackMessage
- 在HI3531上移植和运行QT4.8.6
- JSTL的配置以及使用
- php使用Header函数,PHP_AUTH_PW和PHP_AUTH_USER做用户验证
- java 输入输出流和File简单解析(附android中文乱码问题解决)
- include Return 的应用
- 删除svn目录
- 静态HTML页面处理参数
- hiho#1038 : 01背包 (动态规划)
- 0504
- docker学习记录
- 从数据库得到的结果集存放到List集合中
- poj3254 Corn Fields (状态压缩)