---
# System prepended metadata

title: longest common subsequence 優化

---

# longest common subsequence 優化

:::success
基礎LIS作法只有$O(n^2)$，但利用patience sorting & bit可以到O(nlogn)
:::

patience sorting
--
* 假設有一撲克牌序列，以及一個存放處理完的撲克牌的地方
* **規則**：
    1. 每次取一張
    2. 從最左邊的一疊開始，如果那一疊牌的最上方比目前拿的牌還小，那就再往左邊一疊看，直到最上方的牌比目前還大，就疊上去。否則找不到的話就建立新的一疊。
* 示意：
![](https://i.imgur.com/DGxvUJT.png)

    順序：
    ![](https://i.imgur.com/oSToCSq.png)

> source:https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/LongestIncreasingSubsequence.pdf

lis
--
* 利用patience sort, lis即為撲克牌的疊數，如上圖是5。
* 原因：
    * 在第n疊牌中，每個第0~n-1疊中一定有一張（不一定是最上層）是比第n疊其中最上層還小。因為就規則而言，只要比最上層大，那就要往右邊走，所以就算之後在第n-1疊中加入比第n疊的最上層還大的牌，n-1中的第二張還是比較小。
    * 而每一次把一張牌疊上去，可以視為把標準拉低，因為發現有比目前最上層還小的牌，所以更容易讓lis增大。

程式碼：
```cpp=
#include <bits/stdc++.h>

using namespace std;

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;

    vector<int> val(n);
    for(int i=0;i<n;++i) cin >> val[i];

    vector<int> cur;
    cur.push_back(val[0]);

    for(int i=1;i<n;++i){
        if(val[i]>cur.back())
            cur.push_back(val[i]);
        else
            *lower_bound(cur.begin(), cur.end(), val[i])=val[i];
    }

    cout << cur.size() << "\n";
}

```