Prob I. Just LIS
You are to find the length of the longest increasing subsequence (LIS) of a given sequence A
whose length is n
.
Input
There multiple test cases. Each case contains n+1
integers. The first integer is n
. The following n
intgers give the sequence A
. The input is terminated by EOF
.
Output
For each case, output the length of LIS in a single line.
Restraints
There are 10
cases.
0<=n<=10^5
Sample
Input | Output |
---|---|
3 3 2 1 4 3 3 4 1 5 9 7 3 8 4 | 1 2 2 |
这道题目是3.16日周赛的题目,有一个复杂度为O(nlogn)的算法。代码如下:
#include<iostream>
#include<algorithm>
#define MAX 100000
#define INF 100000000
using namespace std;
int seq[MAX];
int dp[MAX];
int main()
{
int n;
while(cin>>n){
for(int i = 0; i < n; i++)
cin>>seq[i];
fill(dp, dp+n, INF);//对dp[]赋值为INF
for(int i = 0; i < n; i++)
*lower_bound(dp, dp+n, seq[i]) = seq[i];
cout<<lower_bound(dp, dp+n, INF) - dp<<endl;
}
return 0;
}
1.输入数据时首先将序列的n个元素都存储在seq[ ]数组中
2. *lower_bound(dp, dp+n, seq[i]) = seq[i];的意思就是在数组dp[ ]中,且地址从dp到dp+n的左闭右开区间内找到第一个大于等于seq[i]值的地址,并将seq[i]的值放到这个地址当中。(大家可以去搜索有关lower_bound()函数的用法)
从上面那道题目我发现,这种前面所采用的方法虽然简洁且效率高,但是没有办法输出符合题目要求的子序列,于是就有了下面的方法,但是以下的方法的时间复杂度又提高了,变成了O(n^2);
#include<iostream>
#define MAX 100000
using namespace std;
int a[MAX], dp[MAX];
void Output_LIS(int res, int n);
int main()
{
int n;
while(cin>>n){
int res = 0;
for(int i = 0; i < n; i++)
cin>>a[i];
for(int i = 0; i < n; i++){
dp[i] = 1;
for(int j = 0; j < i; j++)
if(a[j] < a[i])
dp[i] = max(dp[i] , dp[j]+1);
res = max(res, dp[i]);
}
cout<<res<<endl;
Output_LIS(res, n-1);
cout<<endl;
}
return 0;
}
//这个输出子序列的函数很重要
void Output_LIS(int res, int n)
{
if(n < 0 || res == 0) return;//如果n<0或者子序列的长度为0则退出
int tag = 0;
if(dp[n] == res){
tag = 1;
res--;
}
Output_LIS(res, --n);
if(tag) cout<<a[n+1]<<' ';
}
但是当有多个子序列满足题目要求的时候,这个代码又只能输出一组结果,比如:输入4 3 3 2 1时,只会输出一个子序列1。不知道大家有神马方法可以将所有满足要求的结果都输出?