【dp】求最長上升子序列
阿新 • • 發佈:2019-04-26
輸出 個數 getchar() 輸入 長度 %d pri get 描述
題目描述
給定一個序列,初始為空。現在我們將1到N的數字插入到序列中,每次將一個數字插入到一個特定的位置。我們想知道此時最長上升子序列長度是多少?
輸入
第一行一個整數N,表示我們要將1到N插入序列中,接下是N個數字,第k個數字Xk,表示我們將k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)
輸出
1行,表示最長上升子序列的長度是多少。
樣例輸入
3
0 0 2
樣例輸出
2
提示
100%的數據 n<=100000
【思路】:
就是用dp表示前i個的最長上升子序列長度,註意一開始賦值成1(坑了我一把,嗚嗚嗚),然後考慮當前點放到序列裏不,然後就ok了.
代碼:O(N2)
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<vector> #include<map> #include<string> #include<cstring> using namespace std; inline int read() {char c = getchar(); int x = 0, f = 1; while(c < ‘0‘ || c > ‘9‘) { if(c == ‘-‘) f = -1; c = getchar(); } while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = getchar(); return x * f; } int a[10080],n,ans,dp[10000]; int main() { cin>>n;for(int i=1; i<=n; ++i) { cin>>a[i]; dp[i]=1; } for(int i=2; i<=n; ++i) { for(int j=1; j<i; ++j) { if(a[i]>a[j]&&dp[j]+1>dp[i]) { dp[i]=dp[j]+1; } } } for(int i=1; i<=n; ++i) { if(dp[i]>ans) { ans=dp[i]; } } cout<<ans; return 0; }
優化代碼:O(n*logn)
【思路】:
用二分查找,可是二分很難怎麽辦?
lower_bound( begin,end,num):從數組的begin位置到end-1位置二分查找第一個大於或等於num的數字 lower_bound( begin,end,num):從數組的begin位置到end-1位置二分查找第一個大於或等於num的數字
竟然可以直接二分,那還慫個P。
更多解釋見https://www.cnblogs.com/wxjor/p/5524447.html(和這篇博客學的)
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<vector> #include<map> #include<string> #include<cstring> using namespace std; const int maxn=99999; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < ‘0‘ || c > ‘9‘) { if(c == ‘-‘) f = -1; c = getchar(); } while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = getchar(); return x * f; } int a[maxn],d[maxn],n; int len=1; int main() { scanf("%d",&n); for(int i=1; i<=n; i++) scanf("%d",&a[i]); d[1]=a[1]; for(int i=2; i<=n; i++) { if(a[i]>d[len]) d[++len]=a[i]; else { int j=lower_bound(d+1,d+len+1,a[i])-d; d[j]=a[i]; } } printf("%d\n",len); return 0; }
【dp】求最長上升子序列