zcmu 2112 聪明的美食家(最长上升子序列nlogn做法)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39562952/article/details/81332783

思路:

最长上升子序列(LIS)的典型变形,熟悉的n^2的动归会超时。LIS问题可以优化为nlogn的算法。
定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则记录最小的那个最末元素。
注意d中元素是单调递增的,下面要用到这个性质。
首先len = 1,d[1] = a[1],然后对a[i]:若a[i]>d[len],那么len++,d[len] = a[i];
否则,我们要从d[1]到d[len-1]中找到一个j,满足d[j-1]<a[i]<d[j],则根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 d[j] = a[i];
最终答案就是len
利用d的单调性,在查找j的时候可以二分查找,从而时间复杂度为nlogn。

https://blog.csdn.net/shuangde800/article/details/7474903

代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#define maxn 200000+100
using namespace std;

int b[maxn];
int main()
{
	int n;
	int t,ans;
	while (cin >> n)
	{
		ans = 0;
		memset(b, 0, sizeof(b));
		
		b[0] =-1;
		ans++;
		for (int i = 0; i < n; i++)
		{
			cin >> t;
			if (t >= b[ans - 1])
			{
				b[ans++] = t;
			}
			else
			{
				int z = upper_bound(b, b + ans, t)-b;
				b[z] = t;
			}
		}
		cout << ans-1 << endl;
	}
	

	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39562952/article/details/81332783