AcWing 1017. 怪盗基德的滑翔翼——最长上升子序列
最长上升子序列
1、\(O(n^{2})\) 简单DP做法
\[dp[i]=\max_{h[j] < h[i]} [dp[j] + 1]
\]
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int h[N];
int dp[N];
int main() {
int T; cin >> T;
while(T --) {
int n; cin >> n;
for(int i = 1; i <= n; ++ i) cin >> h[i];
memset(dp, 0, sizeof(dp));
int res = 0;
for(int i = 1; i <= n; ++ i) {
for(int j = 1; j < i; ++ j) {
if(h[i] > h[j]) dp[i] = max(dp[i], dp[j] + 1);
}
res = max(res, dp[i]);
}
memset(dp, 0 ,sizeof(dp));
for(int i = 1; i <= n; ++ i) {
for(int j = 1; j < i; ++ j) {
if(h[i] < h[j]) dp[i] = max(dp[i], dp[j] + 1);
}
res = max(res, dp[i]);
}
cout << res + 1 << endl;
}
return 0;
}
2、\(O(nlogn)\)的二分+贪心法
简单来说:就是q[i]表示所有序列为i的上升序列的最小末尾元素, 如[1,2,3],[5,4,2]这种长度为3的序列,那么q[3]=2。这样处理到第i位数字前,q数组就维护了[1~i-1]所有序列的最小最后一个元素,那么想想看能把h[i]加在哪个位置,那么dp[i]=该位置编号。 至于这个位置就是第一个大于等于h[i]的位置。
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int h[N];
int q[N];
int main() {
int T; cin >> T;
while(T --) {
int n; cin >> n;
for(int i = 1; i <= n; ++ i) cin >> h[i];
memset(q, 0x3f3f3f3f, sizeof(q));
int res = 0;
for(int i = 1; i <= n; ++ i) {
int x = h[i];
int tx = lower_bound(q + 1, q + n + 1, x) - q;
q[tx] = x;
res = max(res, tx);
}
memset(q, 0x3f3f3f3f, sizeof(q));
for(int i = n; i >= 1; --i) {
int x = h[i];
int tx = lower_bound(q + 1, q + n + 1, x) - q;
q[tx] = x;
res = max(res, tx);
}
cout << res << endl;
}
return 0;
}
3、\(O(nlogn)\) 树状数组优化
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int h[N];
int q[N];
int c[N];
// 树状数组维护区间最大值模板
int lowbit(int x){ return x & -x;}
int ask(int x) {
int ans = 0;
for(; x; x -= lowbit(x)) ans = max(ans, c[x]);
return ans;
}
void add(int x, int y) {
for(; x < N; x += lowbit(x)) c[x] = max(c[x], y);
}
int main() {
int T; cin >> T;
while(T --) {
int n; cin >> n;
for(int i = 1; i <= n; ++ i) cin >> h[i];
int res = 0;
memset(c, 0, sizeof(c));
for(int i = 1; i <= n; ++ i) {
add(h[i], ask(h[i] - 1) + 1);
}
res = max(res, ask(N - 1));
memset(c, 0, sizeof(c));
for(int i = n; i >= 1; -- i) {
add(h[i], ask(h[i] - 1) + 1);
}
res = max(res, ask(N - 1));
cout << res << endl;
}
return 0;
}