动态规划求最长递增子序列(BJFUOJ 1482)

来源:互联网 发布:nginx io模型 编辑:程序博客网 时间:2024/05/21 14:54

Ivan的决心

时间限制(C/C++):1000MS/3000MS          运行内存限制:65536KByt

描述

    Ivan看到好多大神仅仅用一年的时间就可以摘金夺银,走上人生的巅峰,Ivan羡慕钦佩的同时暗暗下定了决心,每天进步一点点,实现自己大一时定下的目标。

    众所周知,刷题是进步最快的办法了,Ivan有一个神奇的题库,里面有近十万道题目,每道题目都有对应的难度系数,因为题库实在是太大了,Ivan只愿意按题号递增的顺序做题,同时Ivan每天都需要进步,所以Ivan做的题目的难度系数也是递增的,Ivan不会去做任何和曾经做过的题目难度一样甚至更低的题目。

    Ivan想知道他按这样的方式做这样一个题库最多能够刷多少道题,聪明的小伙伴帮帮他吧。


输入

输入包含多组测试数据,每组测试数据第一个数字为n,表示题库总题数n。接下来一行为n个整数ai表示第i个题目的难度系数。(0<=n<=105,0<=ai<=109

输出

对应每组测试数据,输出Ivan最多可以做的题数,每组输出占一行。



该题是一道动态规划求最长递增子序列的长度,而且对时间有限制,只可能是O(n)或O(nlogn)的时间复杂度。因此普通的dp是无法ac的。


因此要换一种思路来求最长的长度。

因为题目要求是一道求最长递增子序列的长度,所以我们可以不用关心最长子序列的每位值是多少,因此,可以用一个开一个十万大小的数组来保存子序列每个长度位的最小末尾值

之后只需要遍历数组一次,只要找到子序列数组中存在值比当前值大的数,就替换之,如果没有找到,就在末尾添加,并且长度加一。

遍历的复杂度是O(n),但查找的复杂度也是O(n),所以整体的时间复杂度还是O(n2),仍不符合题目要求,因此,还可以使用二分查找对查找进行优化。这样时间复杂度就可以达到O(nlongn)了

#include<iostream>#include<stdio.h>#include<math.h>#include<string>#include<string.h>#include<vector>#include<stack>#include<queue>#include<map>#include<algorithm>using namespace std;int a[100005],f[100005];int main(){   int n;while(scanf("%d",&n)!=EOF){memset(a,0,sizeof(a));memset(f,0,sizeof(f));for(int i=0;i<n;i++)scanf("%d",&a[i]);int len=0;for(int i=0;i<n;i++){int pos=lower_bound(f,f+len,a[i])-f;//二分查找第一个大于当前数字的位置if(pos==len)//如果不存在,将数字放在队尾,长度加一{f[len]=a[i];len++;}else//如果查到,用该较小的数替换较大的数{f[pos]=a[i];}}printf("%d\n",len);}return 0;}




0 0
原创粉丝点击