• P4303 [AHOI2006]基因匹配


    P4303 [AHOI2006]基因匹配

    题目链接https://www.luogu.com.cn/problem/P4303

    大意 给出一个n,和两个长度为 5n 的序列,这两个序列中,1-n每个数都出现5次,求最长公共子序列。

    Sample input

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

    Sample output

    8
    

    分析

    n最大20000,按通常求lcs的方法会t掉

    注意一下这两个序列的特殊性,有很多重复的元素。

    我们可以记录一下每种元素的位置,拿样例举个栗子吧:

    对于序列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中的元素对应起来。

    而我们把位置变成倒序,是为了保证每个点只取了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
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    交通部道路运输车辆卫星定位系统部标JTT808、809、796标准大全
    linux下如何源码编译安装vim
    Ubuntu如何重新启动tftp服务
    Ubuntu如何自定义tftp服务根目录
    git如何撤销git add操作?
    如何使两台主机间的不同网段互通?
    debian下如何源码安装tmux
    mysql插入数据自动生成主键uuid
    mysql的 UUID的生成方式
    MySQL SQL语句 生成32位 UUID
  • 原文地址:https://www.cnblogs.com/hzoi-poozhai/p/12756220.html
Copyright © 2020-2023  润新知