《艾爾登法環》力智流魔法騎士BD參考
阿新 • • 發佈:2022-03-20
最長上升子序列的nlogn的做法非常奇妙,學完在這裡做個總結。
關於最長上升子序列,最基礎的做法就是n2做法,判斷從第一個點的位置到某個點這一段的最長上升子序列的長度就是要枚舉出這個點的前面的點中比它小的裡最長上升子序列長度最長的那個,在此基礎上加1。
下面是重點,nlogn的做法。
思路:
1.需要一個數組,陣列在最開始定義為一個空陣列。
2.從1到n,判斷每個位置:
(1)這個位置的數比這個陣列的最後一個數大,則將這個數放入陣列的最後一個數的後面。
(2)否則,二分查詢,找到陣列中第一個比這個數大的數,將它替換。
3.最長上升子序列的長度就是陣列的長度。
原理:
陣列中存的數就是從一到這個數的中間部分的最長上升子序列的長度為陣列中這個數所在位置的下標的數中最小的一個,陣列中的最後一個數就是目前最長上升子序列的最後一個數,若正在判斷的數比最後一個數大,則說明最長上升子序列的長度增加;而另一種情況則是替換陣列中第一個比它大的數,替換的這個位置的下標就是從一到這個數的中間部分的最長上升子序列的長度,那前面的數為什麼不替換呢,原因前面已經講了,就是在這個位置的必須是最小的,那麼按這個原理判斷到最後,陣列長度就是最長上升子序列的長度。
這有一道題目:
洛谷P1439 【模板】最長公共子序列
題目描述
給出 1,2,…,n 的兩個排列 P1 和 P2 ,求它們的最長公共子序列。
輸入格式
第一行是一個數 n。
接下來兩行,每行為 n 個數,為自然數 1,2,…,n 的一個排列。
輸出格式
一個數,即最長公共子序列的長度。
輸入輸出樣例
輸入 #15 3 2 1 4 5 1 2 3 4 5輸出 #1
3
說明/提示
- 對於 50% 的資料, n≤103;
- 對於 100% 的資料,n≤105。
105,非常顯然n2做法一定超時,那麼它要怎麼做呢,可以將最長公共子序列問題轉化為最長上升子序列問題(將p2陣列中的數變成p1陣列中對應的下標,求p2的最長上升子序列),接著用上面的nlogn方法求就可以了。
下面是程式碼:
#include<iostream> using namespace std; int n; int p1[100010],p2[100010]; int wei[100010]; int cnt=0; int zxl[100010]; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>p1[i]; wei[p1[i]]=i; } for(int i=1;i<=n;i++){ cin>>p2[i]; p2[i]=wei[p2[i]]; } for(int i=1;i<=n;i++){ if(p2[i]>zxl[cnt]){ zxl[++cnt]=p2[i]; } else{ int l=1; int r=cnt; int mid=(l+r)/2; while(l<r){ if(p2[i]>zxl[mid]){ l=mid+1; } else{ r=mid; } mid=(l+r)/2; } zxl[l]=p2[i]; } } cout<<cnt; return 0; }