最长上升子序列问题

本篇包含题目:code[vs] 2188 最长上升子序列    code[vs] 1576 最长严格上升子序列

DP思想:

状态:dp[i]表示以第i个数为结尾的最长上升子序列长度。
阶段:按下标划分阶段。这样只会从左往右转移。
状态转移方程
dp[i] = max(dp[i], dp[j]+1);(j < i && num[j] < num[i])

时间复杂度为O(n^2)。

codevs 2188 最长上升子序列

题目描述 Description

LIS问题是最经典的动态规划基础问题之一。如果要求一个满足一定条件的最长上升子序列,你还能解决吗?
给出一个长度为N整数序列,请求出它的包含第K个元素的最长上升子序列。
例如:对于长度为6的序列<2,7,3,4,8,5>,它的最长上升子序列为<2,3,4,5>,但如果限制一定要包含第2个元素,那么满足此要求的最长上升子序列就只能是<2,7,8>了。

输入描述 Input Description

第一行为两个整数N,K,如上所述。
接下来是N个整数,描述一个序列。

 输出描述 Output Description

请输出两个整数,即包含第K个元素的最长上升子序列长度。

样例输入 Sample Input

8 6
65 158 170 299 300 155 207 389

样例输出 Sample Output

4

数据范围及提示 Data Size

80%的数据,满足0<n<=1000,0<k<=n
100%的数据,满足0<n<=200000,0<k<=n

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int num[210005], g[210005];
const int inf = 23333333;
int main()
{
	int n, k;
	cin>>n>>k;
	for(int i = 1;i <= n;i ++)
		scanf("%d", &num[i]);
	for(int i = 1;i <= n;i ++)
		g[i] =inf;
	for(int i = 1;i <= n;i ++)
	{
		int j = lower_bound(g+1, g+n+1, num[i])-g;
		if((num[i] <= num[k] && i <= k) || (num[i] > num[k] && i > k))
			g[j] = num[i];
	}
	int ans, maxx = -1;
	for(int i = n;i >= 1;i --)
	{
		if(g[i] > maxx && g[i] != inf)
		{
			maxx = g[i];
			ans = i;
		}
	}
	cout<<ans;
	return 0;
}

codevs 1576 最长严格上升子序列

题目描述 Description

给一个数组a1, a2 … an,找到最长的上升降子序列ab1<ab2< .. <abk,其中b1<b2<..bk。
输出长度即可。

输入描述 Input Description

第一行,一个整数N。
第二行 ,N个整数(N < = 5000)

输出描述 Output Description

输出K的极大值,即最长不下降子序列的长度

样例输入 Sample Input

5
9 3 6 2 7

样例输出 Sample Output

3

【样例解释】

最长不下降子序列为3,6,7

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int num[23333], dp[23333];
int main()
{
	int n;
	cin>>n;
	for(int i = 1;i <= n;i ++)
	{
		scanf("%d", &num[i]);
	}
	int ans = 0;
	for(int i = 1;i <= n;i ++)
	{
		dp[i] = 1;
		for(int j = 1;j < i;j ++)
		{
			if(num[j] < num[i])
				dp[i] = max(dp[i], dp[j] + 1);
			ans = max(dp[i], ans);
		}
	}
	cout<<ans<<endl;
	return 0;
}

 

上一篇
下一篇