利用lower_bound()和upper_bound()解決最長嚴格(非)上升/下降子序列長度問題
阿新 • • 發佈:2021-10-08
一、lower_bound()
與upper_bound()
基操
lower_bound()
:STL
,返回某一給定容器區間內第一個大於等於某給定數字x
的數字的指標。
upper_bound()
:STL
,返回某一給定容器區間內第一個大於某給定數字x
的數字的指標。
以下均以lower_bound()
為例
-
基本操作
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;
-
更改比較方式
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; }