UVA1471防线

https://blog.csdn.net/accelerator_/article/details/38819873
题意:给定一个序列,要求删去一个连续子序列后,得到的序列中有一个最长的连续递增序列,输出此最长连续递增序列的长度

思路
先左右扫描一遍,把每个位置往左和往右的最大连续长度记录下来,存在left和right数组里。数组 v 用来记录向左长度 i 的序列,最后一位的最小值。这个序列是满足单调性的,因为递增序列肯定是1,2,3,4…这样不断往上加的,如果遇到一个a[i]比较小的,就更新 v 相应长度下的值,这样在这个单调递增的序列中,每次就可以二分找出最后一位小于a[i],然后和当前位置往右的最大连续序列长度right[i]拼接起来,(也就是说,我们总是让当前位置向右是连续的,假设向左的那部分有剪切),得到一个长度,记录下最大值就是答案。

#include 
#include 
using namespace std;
const int N = 200000+5;
const int INF = 1<<30;
int A[N], left[N], right[N] ;
int v[N]; // v[i]:长度为 i 的序列,最后一位的最小值 
int main()
{
	//freopen("in.txt","r",stdin);
	int T,n; scanf("%d",&T);
	while( T-- ){
		scanf("%d",&n);
		for( int i=0; iA[i-1] ) left[i] = left[i-1]+1;
			else left[i] = 1;
		}
		// right[i]: i 向右走最长的连续序列长度
		right[n-1] = 1;
		for( int i=n-2; i>=0; --i ){
			if( A[i]

用set

#include 
#include 
using namespace std;
const int N = 200000+5;
int n, A[N], left[N], right[N];

struct Candidate{
	int a,l;// 值,向左的长度 
	Candidate( int x,int y):a(x),l(y){}
	bool operator<( const Candidate& rhs )const{
		return a s;

int main()
{
	//freopen("in.txt","r",stdin);
	int T; scanf("%d",&T);
	while( T-- ){
		
		scanf("%d",&n);
		for( int i=0; i=0; --i ){
			if( A[i]::iterator it = s.lower_bound(c); //指向>=c的最小的那个
			if( it!=s.begin() ){
				Candidate last = *(--it); // (it-1)指向最后 =c.l ) keep = false;
			}
			// 如果加入,更新候选表 
			if( keep ){
				s.erase( c ); // 如果c之前存在,那么以前的c的l一定 <= 新c的l ,因为c是递增的 
				s.insert( c );
				it = s.find( c );
				++it;
				//淘汰无用的元素
				while( it!=s.end() && it->a > c.a && it->l <= c.l ) s.erase( it++ );
			}
		}
		printf("%d\n",ans);
	
	}
	//fclose(stdin);
	return 0;
}

你可能感兴趣的:(UVA,二分,贪心,Practice)