# 最長遞增子序列
## Longest Increasing Subsequence
----
### 小知識
#### Subsequence 子序列 -> 不用連續
#### Subarray 子串 -> 要連續
---
## [題目敘述](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=b032)
給一個長度為 $N$ 的正整數序列 $A$
求最長嚴格遞增子序列長度
即求一序列 $B$ 滿足
$B_1<B_2<B_3 ...<B_k$ ( $k$ 即為答案)
$A_{B_1}<A_{B_2}<A_{B_3}...<A_{B_k}$
>$N<=100$
----
### Sample
```
A = 9 3 7 4 5 2 6
B = 2 4 5 7 // (位置)不一定是唯一
LIS = 3 4 5 6 // (內容)不一定是唯一
k = 4
```
---
### 怎麼寫?
按照慣例,設 $dp[i]$ 為由左到右
最後一個位置選 $i$ 的最大長度
最後答案為 $max$ { $dp[i]$ } { $1<=i<=N$ }
----
### 轉移?
$dp[i]=1+max$ { $dp[j]$ } { $j<i$ , $A_j<A_i$ }
簡單來說,就是在滿足
1. 位置在自己前面
2. 數字比自己小
的 $dp[j]$ 中選一個最大的,接在他後面
----
### 實作
```cpp=
#include<iostream>
using namespace std;
const int N=105;
int n,ans,a[105];
int main(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
for(int j=0;j<i;j++)
if(a[j]<a[i]){
dp[i]=max(dp[i],1+dp[j]);
ans=max(ans,dp[i]);
}
cout<<ans<<endl;
}
```
複雜度? $O(N^2)$
---
## 你以為醬就結束了嗎
----
### [再來一題](https://cses.fi/problemset/task/1145/)
> $N<=2\times10^5$
### 嗨呀!!!
不能 $O(N^2)$ 了怎麼辦?
----
### 直接看做法
1. 維護一個嚴格遞增序列 $X$
2. 從左到右遍歷 $A_i$
```cpp=
if( A[i] > X 中所有元素){
將 A[i] 放到 X 的最後 // 情況 1
}
else{
將 X 中第一個大於等於 A[i] 換成 A[i] // 情況 2
}
```
----
### 看個栗子(?
```
A = 9 3 7 4 5 2 6
-------------------
i=1 A[i]=9
X是空的 -> 情況 1
X = 9 // 把 9 放到 X 的最後
-------------------
i=2 A[i]=3
3 < 9 -> 情況 2
X = 3 // 把 9 換成 3
-------------------
i=3 A[i]=7
7 > 3 -> 情況 1
X = 3 7 // 把 7 放到 X 的最後
-------------------
i=4 A[i]=4
4 < 7 -> 情況 2
X = 3 4 // 把 7 換成 4
-------------------
i=5 A[i]=5
5 > 4 -> 情況 1
X = 3 4 5 // 把 5 放到 X 的最後
-------------------
i=6 A[i]=2
2 < 3 -> 情況 2
X = 2 4 5 // 把 3 換成 2
-------------------
i=7 A[i]=6
6 > 5 -> 情況 1
X = 2 4 5 6 // 把 6 放到 X 的最後
```
----
### $X$ 能幹嘛
1. $X$ 的長度即為 LIS 的長度
2. $X$ 不是真正的 LIS
剛剛求出的 $X$ 是 2 4 5 6
但真正的 $LIS$ 是 3 4 5 6
----
### 順便一提
$dp[i]$ 就是 $A_i$ 放進 $X$ 的位置
比如說:
$A_i$ 放在 $X$ 中的第 $2$ 個位置, $dp[i]=2$
---
### 另一種做法
其實我們想要找的就是 $max$ { $dp[j]$ } { $j<i$ , $A_j<A_i$ }
因此我們可以用資料結構來維護這個東西
需要的操作有
1. 單點改值
2. 區間求最大值
在由前往後遍歷時,對於每個 $A[i]$ 維護最大的 $dp[i]$
每次要求 $dp[i]$ 時,在 $0$ ~ $A[i]$ 中取 $dp[j]$ 最大值 $+1$ 就可以了
可以用 BIT 或 線段樹 或其他神秘的資結
---
### 怎麼求真正的 LIS
如果有一個 $A_j$ 滿足:
$A_j<A_i$ 和 $dp[j]=dp[i]-1$
那麼 $A_i$ 就可以接在 $A_j$ 的後面
----
### 再來個栗子
```
A : 9 3 7 4 5 2 6
dp : 1 1 2 2 3 1 4
```
對於第 $4$ 個位置, $A_4=4$ , $dp[4]=2$
可以發現 $dp[1]$ 和 $dp[2]$ 都是 $(dp[4]-1)=1$
但只有 $A_2=3$ 比 $A_4=4$ 小
因此在真正的 $LIS$ 中, $A_3$ 就可以接在 $A_2$ 後面
---
## 刷題時間
----
很多 $LIS$ 的題目都是難在看不出他是 $LIS$
只要看出來通常就可以快樂 AC 啦~
----
[2021/1 APCS p4 飛黃騰達](https://zerojudge.tw/ShowProblem?problemid=f608)
[UVa 00481 What Goes Up](https://zerojudge.tw/ShowProblem?problemid=d242)
[2021 TOI 入營考 pC 粉刷護欄](https://tioj.ck.tp.edu.tw/problems/2195)
[UVa 11456 Trainsorting](https://zerojudge.tw/ShowProblem?problemid=d052)