1 条题解

  • 0
    @ 2025-8-24 21:58:45

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar clockwhite
    失去的都是已知的,得到的都是未知的

    搬运于2025-08-24 21:58:45,当前版本为作者最后更新于2020-12-01 16:16:36,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P4303 基因匹配

    前言

    ​ 因为看到这题没有人用偏序的讲法感到十分奇怪,就来整一发。

    Solution

    ​ 首先这是一个 LCS 问题,而在最长公共子序列的题解之中可以找到大量关于 LCS 的解决方案。

    ​ 以下简要阐述我关于如何将 LCS 转化为 LIS 的简要概括。

    • 对于任意公共子序列 S=s1s2s3...skS=s_1s_2s_3...s_k ,对于其中某元素 sis_i 记它在第一个串中的位置为 aia_i 在第二个串中为 bib_i
    • 那么 i>1,ai>ai1,bi>bi1\forall i > 1,a_i>a_{i-1},b_i>b_{i-1} 恒成立

    于是这个问题就变成了一个二维偏序问题,这也是 LIS 的经典解法。

    ​ 如果说不知道什么是二维偏序,可以上网搜索。以下给出简要理解。二维偏序是一种要求同时满足两个偏序关系(两个不等式)的计数问题。可以先通过排序解决一个不等式,然后再用数据结构或CDQ等方式解决。

    ​ 此处使用权值树状数组,记录位置早于 x 的最大值。值得一提的是,以在第二个串中的下标顺序计算可以直接符合一个偏序,无需排序。

    ​ 用几何的方式来解释,即以某个字符在第二个串中的位置作为横坐标,在第一个串中的可能位置为纵坐标,在坐标系上建立一个点。

    ​ 最后要求一个单增函数经过尽可能多的点。树状数组可以快速算出纵坐标处于 y=αy=\alpha 这样一条水平线下的最大值。

    ​ 还有一个小细节,最朴素去做的话,应该是一个横坐标对应的五个点一起算出来再加入树状数组,因为要求纵坐标严格小于。但是如果纵坐标从上往下枚举,答案就不会相互影响。类似于0/1 背包。

    ​ 代码内附注释。

    CODE

    #define fe(i,a,b) for(int i=a;i<=b;++i)
    inline int read()//快读
    const int MAXN=1e5+5;
    int n,x,bet[MAXN];
    vector<int> pos[MAXN];//记录每个数字在第一个串中的位置
    inline int lowbit(int x){return x&(-x);}//树状数组部分
    inline void add(int x,int y){for(;x<=n;x+=lowbit(x))bet[x]=max(bet[x],y);}
    inline int query(int x){return x?max(query(x-lowbit(x)),bet[x]):0;}
    int main(){
    	n=read()*5;//长度是五倍
    	fe(i,1,n)pos[read()].push_back(i);
    	fe(i,1,n)for(int j=4,x=read();j>=0;--j)add(pos[x][j],query(pos[x][j]-1)+1);
        //倒序枚举位置,计算的同时更新,-1是因为严格小于,+1是因为计算答案
    	printf("%d",query(n));//上界之下的最大值就是答案
    	return 0;
    }
    
    • 1

    信息

    ID
    3272
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者