常规思路:
定义 dp[i]:=以a[i]为末尾元素的最长上升子序列的长度,
以a[i]结尾的上升序列是:
只包含a[i]的序列,
在满足j<i并且aj<ai的以aj为末尾的上升子序列末尾追加上ai得到的子序列。
两者之一。
这样递推关系:dp[i]=max(1,dp[j]+1|j<i&&a[j]<a[i]) 就能在O(n^2)的时间内解决问题.
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <vector> 5 #include <cstring> 6 #include <string> 7 #include <algorithm> 8 #include <string> 9 #include <set> 10 #include <functional> 11 #include <numeric> 12 #include <sstream> 13 #include <stack> 14 #include <map> 15 #include <queue> 16 #pragma comment(linker, "/STACK:102400000,102400000") 17 #define CL(arr, val) memset(arr, val, sizeof(arr)) 18 19 #define ll long long 20 #define inf 0x7f7f7f7f 21 #define lc l,m,rt<<1 22 #define rc m + 1,r,rt<<1|1 23 #define pi acos(-1.0) 24 25 #define L(x) (x) << 1 26 #define R(x) (x) << 1 | 1 27 #define MID(l, r) (l + r) >> 1 28 #define Min(x, y) (x) < (y) ? (x) : (y) 29 #define Max(x, y) (x) < (y) ? (y) : (x) 30 #define lson l,m,rt<<1 31 #define rson m+1,r,rt<<1|1 32 #define E(x) (1 << (x)) 33 #define iabs(x) (x) < 0 ? -(x) : (x) 34 #define OUT(x) printf("%I64d ", x) 35 #define lowbit(x) (x)&(-x) 36 #define Read() freopen("a.txt", "r", stdin) 37 #define Write() freopen("b.txt", "w", stdout); 38 #define maxn 100010 39 #define mod 1000000007 40 using namespace std; 41 int a[1001],dp[1001]; 42 int n; 43 void solve() 44 { 45 int res=0; 46 memset(dp,0,sizeof(dp)); 47 for(int i=0;i<n;i++) 48 { 49 dp[i]=1; 50 for(int j=0;j<i;j++) 51 { 52 if(a[i]>a[j]) 53 { 54 dp[i]=max(dp[i],dp[j]+1); 55 } 56 } 57 res=max(dp[i],res); 58 } 59 printf("%d ",res); 60 } 61 int main() 62 { 63 //freopen("a.txt","r",stdin); 64 scanf("%d",&n); 65 for(int i=0;i<n;i++)scanf("%d",&a[i]); 66 solve(); 67 return 0; 68 }
但是如果重新定义递推关系:
dp[i]:=长度为i+1的上升子序列中末尾元素的最小值(不存在就是INF)
最开始dp[i]的值都初始化为INF,然后由前到后考虑数列的元素,对于每个aj,如果i==0或者dp[i-1]<a[j]的话,就有dp[i]=min(dp[i],aj)进行更新,最终找出使得
dp[i]<INF的最大i+1就是结果,之间实现也是O(n^2)的复杂度,但是还可以进一步优化.
首先dp数列中除INF外是单调递增的,所以可以知道对于每个aj最多只需要一次更新,对于这次更新究竟在什么位置,不必每个遍历,二分搜索就行.
复杂度为O(nlogn).
low_bound函数从已经排好序的序列a中利用二分搜索出指向ai>=k的ai的最小的指针,
upper_bound指向满足ai>k的ai的最小指针。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <vector> 5 #include <cstring> 6 #include <string> 7 #include <algorithm> 8 #include <string> 9 #include <set> 10 #include <functional> 11 #include <numeric> 12 #include <sstream> 13 #include <stack> 14 #include <map> 15 #include <queue> 16 #pragma comment(linker, "/STACK:102400000,102400000") 17 #define CL(arr, val) memset(arr, val, sizeof(arr)) 18 19 #define ll long long 20 #define inf 0x7f7f7f7f 21 #define lc l,m,rt<<1 22 #define rc m + 1,r,rt<<1|1 23 #define pi acos(-1.0) 24 25 #define L(x) (x) << 1 26 #define R(x) (x) << 1 | 1 27 #define MID(l, r) (l + r) >> 1 28 #define Min(x, y) (x) < (y) ? (x) : (y) 29 #define Max(x, y) (x) < (y) ? (y) : (x) 30 #define lson l,m,rt<<1 31 #define rson m+1,r,rt<<1|1 32 #define E(x) (1 << (x)) 33 #define iabs(x) (x) < 0 ? -(x) : (x) 34 #define OUT(x) printf("%I64d ", x) 35 #define lowbit(x) (x)&(-x) 36 #define Read() freopen("a.txt", "r", stdin) 37 #define Write() freopen("b.txt", "w", stdout); 38 #define maxn 100010 39 #define mod 1000000007 40 using namespace std; 41 int a[50001],dp[50001]; 42 int n; 43 void solve() 44 { 45 for(int i=0;i<n;i++) dp[i]=inf; 46 for(int i=0;i<n;i++) 47 { 48 *lower_bound(dp,dp+n,a[i]) = a[i]; 49 } 50 printf("%d ",lower_bound(dp,dp+n,inf)-dp); 51 } 52 int main() 53 { 54 //freopen("a.txt","r",stdin); 55 scanf("%d",&n); 56 for(int i=0;i<n;i++)scanf("%d",&a[i]); 57 solve(); 58 return 0; 59 }