nyoj 214——单调递增子序列(二)——————【二分搜索加dp】
单调递增子序列(二)
时间限制:1000 ms | 内存限制:65535 KB
难度:4
- 描述
-
给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度。
如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5。
- 输入
- 有多组测试数据(<=7)
每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=100000)。
数据以EOF结束 。
输入数据保证合法(全为int型整数)! - 输出
- 对于每组测试数据输出整形数列的最长递增子序列的长度,每个输出占一行。
- 样例输入
-
7 1 9 10 5 11 2 13 2 2 -1
- 样例输出
-
5 1
解题思路:这个题目看着跟求单调递增子序列(一)只是在数据范围上扩大了,其实在做法上也因此改变了。这个在n*log(n)的时间复杂度内是可以解决的,所以这里用到了一种别样的方式。在数组D中存放当前len值时符合条件的单调递增的子序列,每个D[]都是子序列的一个元素。每次在D中查找比当前输入的原始序列元素值大的最小值位置,返回下标。将该位置更新为输入元素,然后判断是否需要将len值增加。#include<bits/stdc++.h> using namespace std; const int maxn=100100; const int INF=1e9; int pos; int D[maxn]; int BinSearch(int l,int r,int key){ while(l<=r){ // printf("%d %d\n",l,r); int mid=(l+r)/2; if(D[mid]<key){ l=mid+1; }else if(D[mid]>key){ r=mid-1; }else{ return l; } } return l; } int main(){ int n,i,j,k; while(scanf("%d",&n)!=EOF){ scanf("%d",&pos); int len=1; D[0]=pos; for(i=1;i<n;i++){ scanf("%d",&pos); j=BinSearch(0,len-1,pos); // printf("%d....\n",j); D[j]=pos; len=j+1>len?j+1:len; } printf("%d\n",len); } return 0; } /* 10 2 3 5 7 4 6 8 9 11 12 6 2 3 1 1 6 8 6 8 9 4 5 6 3 */
学学学 练练练 刷刷刷