1、与原始版本区别
原始版本:\(1≤N≤1000\),本题要求:\(1≤N≤100000\)
\(N\)的数据范围大了\(100\)倍,原始版本的题的时间复杂度是\(O(N^2)\),\(1000^2=1000000\),是\(1e6\),是可以\(1\)秒过的,但如果是\(100000^2=10000000000\),是\(1e10\),超时,需要要优化~
2、题解
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
/*
例 n: 7
arr : 3 1 2 1 8 5 6
stk : 3
1 比 3 小
stk : 1
2 比 1 大
stk : 1 2
1 比 2 小
stk : 1 2
8 比 2 大
stk : 1 2 8
5 比 8 小
stk : 1 2 5
6 比 5 大
stk : 1 2 5 6
stk 的长度就是最长递增子序列的长度
*/
int n, a[N];
//单调栈
int stk[N], idx;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
//第一个数字入栈
stk[++idx] = a[1];
//讨论后面的n-1个数字
for (int i = 2; i <= n; i++) {
//如果该元素大于栈顶元素,将该元素入栈(对后序数字可能有用)
if (a[i] > stk[idx]) stk[++idx] = a[i];
//替换掉第一个大于或者等于这个数字的那个数
else *lower_bound(stk + 1, stk + 1 + idx, a[i]) = a[i];
}
printf("%d\n", idx);
return 0;
}
3、解题思路
栈内记录:【长度为\(i+1\)的递增子串中,末尾元素最小的是\(stk[i]\)】。
理解了这个问题以后就知道为什么新进来的元素要不就在末尾增加,要不就替代第一个大于等于它元素的位置。
这里的【替换】就蕴含了一个贪心的思想,对于同样长度的子串,我当然希望它的末端越小越好,这样以后我也有更多机会拓展。