|
|
|
@ -1,210 +0,0 @@
|
|
|
|
|
##[$AcWing$ $896$. 最长上升子序列 II](https://www.acwing.com/problem/content/description/898/)
|
|
|
|
|
|
|
|
|
|
### 一、题目描述
|
|
|
|
|
|
|
|
|
|
给定一个长度为 $N$ 的数列,**求数值严格单调递增的子序列的长度最长** 是多少。
|
|
|
|
|
|
|
|
|
|
**输入格式**
|
|
|
|
|
第一行包含整数 $N$。
|
|
|
|
|
|
|
|
|
|
第二行包含 $N$ 个整数,表示完整序列。
|
|
|
|
|
|
|
|
|
|
**输出格式**
|
|
|
|
|
输出一个整数,表示最大长度。
|
|
|
|
|
|
|
|
|
|
**数据范围**
|
|
|
|
|
$1≤N≤100000$,
|
|
|
|
|
$−10^9≤数列中的数≤10^9$
|
|
|
|
|
|
|
|
|
|
**输入样例:**
|
|
|
|
|
```cpp {.line-numbers}
|
|
|
|
|
7
|
|
|
|
|
3 1 2 1 8 5 6
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**输出样例**:
|
|
|
|
|
```cpp {.line-numbers}
|
|
|
|
|
4
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- 让表格居中显示的风格 -->
|
|
|
|
|
<style>
|
|
|
|
|
.center
|
|
|
|
|
{
|
|
|
|
|
width: auto;
|
|
|
|
|
display: table;
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
margin-right: auto;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
### 二、贪心+二分优化
|
|
|
|
|
|
|
|
|
|
#### 1、与朴素版本的区别
|
|
|
|
|
|
|
|
|
|
> **朴素版本状态表示**:
|
|
|
|
|
> - 集合:$f[i]$表示从第一个数字开始算,以 $a[i]$<font color='red'><b> 结尾 </b></font>的最长的上升序列长度。
|
|
|
|
|
> - 属性:$max$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
前一版本:$N≤1000$,本题要求:$N≤100000$
|
|
|
|
|
|
|
|
|
|
$N$的数据范围大了$100$倍,前一版本动态规划代码的时间复杂度是$O(N^2)$,$1000^2=1000000$,是$1e6$,是可以$1$秒过的,但如果是$100000^2=10000000000$,是$1e10$,超时,需要要优化~
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 2、贪心+二分算法
|
|
|
|
|
|
|
|
|
|
><font color='red' size=4><b>核心思想:
|
|
|
|
|
对于同样长度的子串,希望它的末端越小越好,这样后面有更多机会拓展它,才有可能使得数列更长。</b></font>
|
|
|
|
|
|
|
|
|
|
> **状态表示**:
|
|
|
|
|
> - 集合:$f[i]$表示长度为$i$的递增子序列中,末尾元素最小的是$f[i]$
|
|
|
|
|
> - 属性:$min$
|
|
|
|
|
|
|
|
|
|
**算法步骤**
|
|
|
|
|
* 扫描每个原序列中的数字:
|
|
|
|
|
* 如果$f$中的最后一个数字$f[idx]$小于当前数字$a[i]$,那么就在$f$的最后面增加$a[i]$
|
|
|
|
|
|
|
|
|
|
* 如果$a[i]$小于$f[idx]$,在$f$中查找并替换第一个大于等于它元素
|
|
|
|
|
|
|
|
|
|
**举栗子模拟**
|
|
|
|
|
<div class="center">
|
|
|
|
|
|
|
|
|
|
| $arr$ | $3$ | $1$ | $2$ | $1$ | $8$ | $5$ | $6$ |
|
|
|
|
|
| ----- | --- | --- | --- | --- | --- | --- | --- |
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
开始时$f[]$为空,数字$3$进入序列
|
|
|
|
|
|
|
|
|
|
<div class="center">
|
|
|
|
|
|
|
|
|
|
| $arr$ | <font color='red'>$3$</font> | $1$ | $2$ | $1$ | $8$ | $5$ | $6$ |
|
|
|
|
|
| ----- | ---------------------------- | --- | --- | --- | --- | --- | --- |
|
|
|
|
|
|
|
|
|
|
| $f$ | <font color='red' size=3><b>$3$</b></font> |
|
|
|
|
|
| --- | ------------------------------------------ |
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$1$ 比 $3$ 小, $3$出序列 ,$1$入序列
|
|
|
|
|
|
|
|
|
|
<div class="center">
|
|
|
|
|
|
|
|
|
|
| $arr$ | $3$ | <font color='red'> $1$ </font> | $2$ | $1$ | $8$ | $5$ | $6$ |
|
|
|
|
|
| ----- | --- | ------------------------------ | --- | --- | --- | --- | --- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| $f$ | <font color='red' size=4><b>$1$</b></font> |
|
|
|
|
|
| --- | ------------------------------------------ |
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$2$ 比 $1$ 大,$2$入序列
|
|
|
|
|
|
|
|
|
|
<div class="center">
|
|
|
|
|
|
|
|
|
|
| $arr$ | $3$ | $1$ | <font color='red'>$2$ </font> | $1$ | $8$ | $5$ | $6$ |
|
|
|
|
|
| ----- | --- | --- | ----------------------------- | --- | --- | --- | --- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| $f$ | $1$ | <font color='red' size=4><b>$2$</b></font> |
|
|
|
|
|
| --- | --- | ------------------------------------------ |
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$1$ 比 $2$ 小,在$f$中找到第一个大于等于$1$的位置,并替换掉原来的数字
|
|
|
|
|
|
|
|
|
|
<div class="center">
|
|
|
|
|
|
|
|
|
|
| $arr$ | $3$ | $1$ | $2$ | <font color='red'>$1$</font> | $8$ | $5$ | $6$ |
|
|
|
|
|
| ----- | --- | --- | --- | ---------------------------- | --- | --- | --- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| $f$ | <font color='red' size=4><b>$1$</b></font> | $2$ |
|
|
|
|
|
| --- | ------------------------------------------ | --- |
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$8$ 比 $2$ 大
|
|
|
|
|
|
|
|
|
|
<div class="center">
|
|
|
|
|
|
|
|
|
|
| $arr$ | $3$ | $1$ | $2$ | $1$ | <font color='red'>$8$</font> | $5$ | $6$ |
|
|
|
|
|
| ----- | --- | --- | --- | --- | ---------------------------- | --- | --- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| $f$ | $1$ | $2$ | <font color='red' size=4><b>$8$</b></font> |
|
|
|
|
|
| --- | --- | --- | ------------------------------------------ |
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$5$ 比 $8$ 小,在$f$中找到第一个大于等于$5$的数字,并替换掉原来的数字
|
|
|
|
|
|
|
|
|
|
<div class="center">
|
|
|
|
|
|
|
|
|
|
| $arr$ | $3$ | $1$ | $2$ | $1$ | $8$ | <font color='red'>$5$</font> | $6$ |
|
|
|
|
|
| ----- | --- | --- | --- | --- | --- | ---------------------------- | --- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| $f$ | $1$ | $2$ | <font color='red' size=4><b>$5$</b></font> |
|
|
|
|
|
| --- | --- | --- | ------------------------------------------ |
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$6$ 比 $5$ 大
|
|
|
|
|
|
|
|
|
|
<div class="center">
|
|
|
|
|
|
|
|
|
|
| $arr$ | $3$ | $1$ | $2$ | $1$ | $8$ | $5$ | <font color='red' size=4><b>$6$ </b></font> |
|
|
|
|
|
| ----- | --- | --- | --- | --- | --- | --- | ------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| $f$ | $1$ | $2$ | $5$ | <font color='red' size=4><b>$6$</b></font> |
|
|
|
|
|
| --- | --- | --- | --- | ------------------------------------------ |
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<font color='blue' size=6><b><center>$f$ 的长度$idx$就是最长递增子序列的长度</center></b></font>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 3、时间复杂度
|
|
|
|
|
$$\large O(N*logN)$$
|
|
|
|
|
|
|
|
|
|
### 四、实现代码
|
|
|
|
|
```cpp {.line-numbers}
|
|
|
|
|
#include <bits/stdc++.h>
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
const int N = 100010;
|
|
|
|
|
|
|
|
|
|
int n, a[N];
|
|
|
|
|
|
|
|
|
|
// 数组模拟栈
|
|
|
|
|
int f[N], fl;
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
cin >> n;
|
|
|
|
|
for (int i = 0; i < n; i++) cin >> a[i];
|
|
|
|
|
|
|
|
|
|
// 1、首个元素入栈
|
|
|
|
|
f[0] = a[0];
|
|
|
|
|
|
|
|
|
|
// 2、后续元素开始计算
|
|
|
|
|
for (int i = 1; i < n; i++) {
|
|
|
|
|
if (a[i] > f[fl])
|
|
|
|
|
f[++fl] = a[i];
|
|
|
|
|
else
|
|
|
|
|
// 利用STL的二分,在f中查找第一个大于等于a[i]的值,并完成替换
|
|
|
|
|
*lower_bound(f, f + fl, a[i]) = a[i];
|
|
|
|
|
}
|
|
|
|
|
// 栈内元素数量就是答案
|
|
|
|
|
printf("%d\n", fl + 1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
```
|