P4303 [AHOI2006]遺伝子マッチング

P4303 [AHOI2006]遺伝子マッチング

タイトルリンクhttps : //www.luogu.com.cn/problem/P4303

効果は、 n個を与え、長さ5Nの二つの配列、これら二つの配列、1-nは、それぞれ数は5回、最長共通部分列を見つけることが表示されます。

入力例

2
1 1 1 1 1 2 2 2 2 2 
1 1 1 2 2 2 2 2 1 1 

出力例

8

分析

nは最大20000、lcを求める通常の方法ではtになります。

これら2つのシーケンスの特殊性に注意してください。多くの繰り返し要素があります。

各要素の位置を記録できます。例として栗を取り上げます。

シーケンス1の場合:1が出現する場所:1 2 3 4 5 2が出現する場所6 7 8 9 10

シーケンス2の要素をそれらの位置に置き換えます。

(1 2 3 4 5)(1 2 3 4 5)(1 2 3 4 5)(6 7 8 9 10)(6 7 8 9 10)(6 7 8 9 10)(6 7 8 9 10)( 6 7 8 9 10)(1 2 3 4 5)(1 2 3 4 5)

位置を逆の順序に変更します(理由):

(5 4 3 2 1)(5 4 3 2 1)(5 4 3 2 1)(10 9 8 7 6)(10 9 8 7 6)(10 9 8 7 6)(10 9 8 7 6)( 10 9 8 7 6)(5 4 3 2 1)(5 4 3 2 1)

lisにこのことを尋ねてください。nlognのアルゴリズムがあります。

原理は何ですか?

シーケンス2の位置は、シーケンス1の要素に対応する昇順を満たす必要があります。

そして、位置を逆の順序に変更して、各ポイントが一度だけ取得されるようにしました

コード

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 1000000;
int n, x, tot, a[maxn], low[maxn];
vector<int> v[maxn];//v[i]存储i可能的位置
signed main(){
    scanf("%d", &n);
    for(int i=1; i<=5*n; i++){
        scanf("%d", &x);
        v[x].push_back(i);记录位置
    }
    for(int i=1; i<=5*n; i++){
        scanf("%d", &x);
        for(int j=4; j>=0; j--){
            a[++tot] = v[x][j];//倒序把顺序存入a
        }
    }
    low[1] = a[1];
    int ans = 1;
    for(int i=2; i<=tot; i++){//对a求lis,不多说
        if(a[i] > low[ans]) low[++ans] = a[i];
        else{
            int x = lower_bound(low+1, low+1+ans, a[i]) - low;
            low[x] = a[i];
        }
    }
    printf("%d\n", ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/hzoi-poozhai/p/12756220.html