利用lower_bound()和upper_bound()解决最长严格(非)上升/下降子序列长度问题

一、lower_bound()与upper_bound()基操

lower_bound():STL,返回某一给定容器区间内第一个大于等于某给定数字x的数字的指针。

upper_bound():STL,返回某一给定容器区间内第一个大于某给定数字x的数字的指针。

以下均以lower_bound()为例

  1. 基本操作

    int a[11] = {0,1,2,3,4,5,6,7,8,9,10};
    int x = 5;
    int* p = lower_bound( x+1, x+10+1 , x );   //对于区间 [ a[1], a[10] ], 同 sort
    cout << p << endl;
    cout << *p << endl;
    cout << a[a-p] << endl;
    
  2. 更改比较方式

    void cmp( int a, int b )
    {
        return a > b;
    }
    
    int* p = lower_bound( x+1, x+10+1, x, cmp );  //由大于等于改为小于等于
    

    或

    int* p = lower_bound( x+1, x+10+1, x, greater<int>() );  //由大于等于改为小于等于
    

二、基本思想与证明

以下以最长上升子序列为例

我们以dp[len]表示数组a[len]中长度为len的上升子序列结尾的最小合法值。

当a[i]大于b[len]:将a[i]直接续在b[]数组之后。

当a[i]小于等于b[len]:在b[]中找到第一个大于等于a[i]的数,用a[i]替换它。

证明:

显然(证毕)。

当a[i]大于b[len],显然将a[i]直接续在b[]数组之后是合法的。

当a[i]小于等于b[len],则b[]中第一个大于等于a[i]的数一定不可能比a[i]优。(上升序列x越小x越能接)。

(证毕)

三、实操

#include <bits/stdc++.h>

using namespace std;

int a[1000], dp[1000],n ,len;

int main()
{
	cin >> n; 
	for( int i = 1; i <= n; ++i )
		cin >> a[i];
		
//------------------------------------------------
		
	//最长上升子序列 	
	dp[1] = a[1]; len = 1;
	for( int i = 2; i <= n; ++i )
	{
	
		if( a[i] > dp[len] )
			dp[++len] = a[i];
			
		else
			*lower_bound( dp+1, dp+len+1, a[i] ) = a[i];
	}
	cout << len << endl;
	
//------------------------------------------------
	
	//最长下降子序列 
	dp[1] = a[1]; len = 1;
	for( int i = 2; i <= n; ++i )
	{ 
		if( a[i] < dp[len] )
			dp[++len] = a[i];
			
		else
			*lower_bound( dp+1, dp+len+1, a[i], greater<int>() ) = a[i];		 
	}
	cout << len << endl;
	
//------------------------------------------------

	//最长不降子序列 	
	dp[1] = a[1]; len = 1;
	for( int i = 2; i <= n; ++i )
	{
	
		if( a[i] >= dp[len] )
			dp[++len] = a[i];
			
		else
			*upper_bound( dp+1, dp+len+1, a[i] ) = a[i];
	}
	cout << len << endl;	
	
//------------------------------------------------
	
	//最长不升子序列 	
	dp[1] = a[1]; len = 1;
	for( int i = 2; i <= n; ++i )
	{
	
		if( a[i] <= dp[len] )
			dp[++len] = a[i];
			
		else
			*upper_bound( dp+1, dp+len+1, a[i], greater<int>() ) = a[i];
	}
	cout << len << endl;	
	
//------------------------------------------------

	return 0;
}
posted @ 2021-10-08 15:34  Sanjar  阅读(150)  评论(0)    收藏  举报