簡単なタイトル:
2を考える(1 \)\〜\(\ N-)に配置されている、見つける最長共通部分列を。
さて、ここにいくつかのアルゴリズムがあります。
アルゴリズム1
\(1 \)〜\(n \)配置かどうかは関係ありません。
\(\ text {LCS} \)のルーチン(つまり、最も長い共通のサブシーケンス)を見つけます。
(F_ {I、J} \ \) を表し\(A_1 \) 〜\(a_iを\)と\(B_1 \) 〜\(b_j \)される最長共通サブシーケンス。次に、境界問題を考慮せずに、
明らかに、現在のビットが等しい場合、それらは一緒に縮小します。それ以外の場合、それらは縮小します。
時間の複雑さ:\(O(n ^ 2)\)。
実際のスコア:\(50ポイント\)。
アルゴリズム2
さて、あなたは百度に行って\(\ text {LCS} \)の方法を検索し、最適な\(\ text {dp} \)が\(O(n ^ 2)\)であることを発見しましたか?
ただし、プロパティに注意してください。両方の配列は\(1 \)〜\(n \)配列です。
今日は何を見せますか?
5
3 2 1 4 5
1 2 3 4 5
ああ、私たちは次の場合に3 2 1 4 5
なる1 2 3 4 5
、つまり関係の確立は次のとおりです。
3 - 1
2 - 2
1 - 3
4 - 4
5 - 5
そして、1 2 3 4 5
それはなった3 2 1 4 5
(ああ、これは純粋に偶然です)。
あなたは、実際に、そのような波を操作することによって、ことが判明\(\テキスト{LCSは} \ ) 本質的に\(b_i \)の数に見出さ\(a_iを\)出現順に配列。
明らかに後の動作波\(a_iを\)ため、その後直接決定される(B_i \)\ \(\テキストLIS} {\) (最長の立ち上がりシーケンス)ことができます。2つの\(x <y \)は明らかに\(a_i \)に対応するため、シーケンスも満たします。
時間の複雑さ:\(O(n \ log n)\)。
実際のスコア:\(100pts \)。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
int a2[N],a1[N],be[N];
int b[N],f[N],ans,n;
int main(){
n=read(); for(int i=1;i<=n;i++)
a1[i]=read(),be[a1[i]]=i; //建立对应关系
for(int i=1;i<=n;i++) a2[i]=read();
for(int i=1;i<=n;i++) {
if(be[a2[i]]>b[ans]) { //正常套路 LIS
b[++ans]=be[a2[i]]; f[i]=ans; continue;
} int t=lower_bound(b+1,b+1+ans,be[a2[i]])-b;
b[t]=be[a2[i]]; f[i]=t;
} printf("%d\n",ans);
return 0;
}