uva 1471 defense lines

如果用O(n^2)是会TLE的,所以只能用O(nlogn)来做。

r[i]是以第i个元素为开头的最长连续递增子序列,l[i]是以第i个元素为结尾的最长连续递增子序列。

Min[i]是长度为i的最长连续递增子序列的最后一个元素的最小值。

Eg:若序列为6 5 4 3 2 1则Min[1]为1。

ans = max(ans, r[i] + len - 1 );为什么要减一,读者自己试一试就知道了。

for(int i = 1; i <= n; i++)
        {
            int len = lower_bound(Min+1, Min+1+n, a[i]) - Min;  //Min+1是由于所有长度的最小值是一
            ans = max(ans, r[i] + len - 1 );
            Min[l[i]] = min(a[i], Min[l[i]]);
        }

 在这里,Min[]一定是从下标1开始由小至大更新值的,因为递增子序列的长度是递增的,只有出现了长度为1的连续递增子序列,才会出现长度为二的递增子序列。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define INF 0x3f3f3f3f;
using namespace std;
int a[10000000];
int l[10000000];
int r[10000000];
int Min[10000000];

int main()
{
	//freopen("ztest.txt","r",stdin);
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(r, 1, sizeof(r));
		memset(l, 1, sizeof(l));
		l[1] = 1;
		int n;
		scanf("%d",&n);
		r[n] = 1;
		for(int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		
		for(int i = n - 1; i >= 1; i--)
		{
			if(a[i+1] > a[i])
				r[i] = r[i+1] + 1;
			else
				r[i] = 1;
		}
		for(int i = 2; i <= n ;i++)
		{
			if(a[i] > a[i-1])
				l[i] = l[i-1] + 1;
			else
				l[i] = 1;
		}
		for(int i = 1; i <= n; i++)
		{
			Min[i] = INF;
		}
		int ans = 0;
		for(int i = 1; i <= n; i++)
		{
			int len = lower_bound(Min+1, Min+1+n, a[i]) - Min;
			ans = max(ans, r[i] + len - 1 );
			Min[l[i]] = min(a[i], Min[l[i]]);
		}
		printf("%d\n",ans);
	}
	return 0;
}
		
		
		
		

猜你喜欢

转载自blog.csdn.net/wukongakk/article/details/81005183