P1439 [テンプレート]最長の共通サブシーケンスのソリューション

CSDN同期

元のタイトルリンク

簡単なタイトル:

2を考える(1 \)\\(\ N-)に配置されている、見つける最長共通部分列を

さて、ここにいくつかのアルゴリズムがあります。

アルゴリズム1

\(1 \)\(n \)配置かどうかは関係ありません

\(\ text {LCS} \)のルーチン(つまり、最も長い共通のサブシーケンス)を見つけます

(F_ {I、J} \ \) を表し\(A_1 \) \(a_iを\)\(B_1 \) \(b_j \)される最長共通サブシーケンス。次に、境界問題を考慮せずに、

\ [f_ {i、j} = \ begin {cases} f_ {i-1、j-1} + 1、a_i = b_j \\ \ max(f_ {i、j-1}、f_ {i-1、 j})\ end {cases} \]

明らかに、現在のビットが等しい場合、それらは一緒に縮小します。それ以外の場合、それらは縮小します。

時間の複雑さ:\(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;
}

おすすめ

転載: www.cnblogs.com/bifanwen/p/12676102.html