单调递增子序列(二)(动态规划)

单调递增子序列(二)

时间限制: 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


本来想使用传统动态规划的方式,数据量过大导致超时,才发现用二分法求解

原理就是用maxv数组来存储最长递增子序列,如果找到某个数对应的位置可以更新,如果后面有更长的递增子序列,那么就会将之前的递增子序列全部覆盖

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;

int dp[100010];
int num[100010];

int find_w(int x, int len)
{
	int l = 1, r= len;
	while(l <= r)//注意!!
	{
		int mid = (l+r)/2;
		if(dp[mid] == x) return mid;
		else if(dp[mid] > x) r = mid-1;
		else l = mid+1;
	}
	return l;
}

int main()
{
	int n;
    while(~scanf("%d", &n))
    {
    	for(int i = 1; i <= n; i++)
    	{
    		scanf("%d", &num[i]);
		}
		
		int len = 1;
		dp[len] = num[1];
		for(int i = 2; i <= n; i++)
		{
			if(num[i] > dp[len])
			{
				dp[++len] = num[i];
			}
			else 
			{
				int pos = find_w(num[i], len);
				dp[pos] = num[i]; 
			}
		}
		cout << len << endl;
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yinghui_yht/article/details/79689253