zoukankan      html  css  js  c++  java
  • 洛谷3763:[TJOI2017]DNA——题解

    https://www.luogu.org/problemnew/show/P3763

    加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状。现在研究人员想知道这个基因在DNA链S0上的位置。所以你需要统计在一个表现出吃藕性状的人的DNA序列S0上,有多少个连续子串可能是该基因,即有多少个S0的连续子串修改小于等于三个字母能够变成S。

    是的这篇代码过不了BZOJ(因为懒得卡了/不想写SAM/不会DC3……众多原因)

    其实容错三次匹配并不吓人,我们可以先跳跃匹配到匹配不上的地方,然后cnt++,继续跳跃……直到匹配完全或者cnt>3为止。

    这个跳跃完全可以枚举起点,然后用SA来求lcp进而实现跳跃匹配以此变成$O(n)$的。

    所以总复杂度是$O(Tnlogn)$的……只要卡卡就能过洛谷。

    当然为了过BZOJ,要么常数优秀(写SAM,然后遍历,每次选择一个节点往下走,如果和当前节点匹配不上则cnt++,匹配复杂度不变但是常数小),要么就学DC3,要么……其实后缀数组卡卡也能过。

    #include<map>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=2e5+5;
    inline int turn(char ch){
        if(ch==0)return 0;
        if(ch=='A')return 1;
        if(ch=='G')return 2;
        if(ch=='C')return 3;
        if(ch=='T')return 4;
        return 5;
    }
    char s[N],p[N];
    int n,rk[N],height[N],w[N],sa[N];
    inline bool pan(int *x,int i,int j,int k){
        int ti=i+k<n?x[i+k]:-1;
        int tj=j+k<n?x[j+k]:-1;
        return ti==tj&&x[i]==x[j];
    }
    void SA_init(){
        int *x=rk,*y=height,r=6;
        for(int i=0;i<r;i++)w[i]=0;
        for(int i=0;i<n;i++)w[turn(s[i])]++;
        for(int i=1;i<r;i++)w[i]+=w[i-1];
        for(int i=n-1;i>=0;i--)sa[--w[turn(s[i])]]=i;
        r=1;x[sa[0]]=0;
        for(int i=1;i<n;i++)
            x[sa[i]]=s[sa[i]]==s[sa[i-1]]?r-1:r++;
        for(int k=1;r<n;k<<=1){
            int yn=0;
            for(int i=n-k;i<n;i++)y[yn++]=i;
            for(int i=0;i<n;i++)
                if(sa[i]>=k)y[yn++]=sa[i]-k;
            for(int i=0;i<r;i++)w[i]=0;
            for(int i=0;i<n;i++)w[x[y[i]]]++;
            for(int i=1;i<r;i++)w[i]+=w[i-1];
            for(int i=n-1;i>=0;i--)sa[--w[x[y[i]]]]=y[i];
            swap(x,y);r=1;x[sa[0]]=0;
            for(int i=1;i<n;i++)
                x[sa[i]]=pan(y,sa[i],sa[i-1],k)?r-1:r++;
        }
    }
    void height_init(){
        int i,j,k=0;
        for(int i=1;i<=n;i++)rk[sa[i]]=i;
        for(int i=0;i<n;i++){
            if(k)k--;
            int j=sa[rk[i]-1];
            while(s[i+k]==s[j+k])k++;
            height[rk[i]]=k;
        }
    }
    int f[N][20],lg[N];
    inline int qpow(int a){return 1<<a;}
    void st_init(){
        for(int i=1;i<=n;i++){
            f[i-1][0]=height[i];
            lg[i]=lg[i-1];
            if((1<<lg[i]+1)==i)lg[i]++;
        }
        for(int j=1;j<=lg[n];j++){
            for(int i=0;i<n;i++){
                if(i+qpow(j)-1>=n)break;
                f[i][j]=min(f[i][j-1],f[i+qpow(j-1)][j-1]);
            }
        }
    }
    int lcp(int i,int j){
        int l=rk[i],r=rk[j];if(l>r)swap(l,r);
        l--;r--;if(r<0)return 0;l++;
        int len=r-l+1,k=lg[len],h=qpow(k);
        return min(f[l][k],f[r-h+1][k]);
    }
    int main(){
        int t;scanf("%d",&t);
        while(t--){
            scanf("%s%s",s,p);
            n=strlen(s);int m=strlen(p);
            s[n++]='#';
            for(int i=0;i<m;i++)s[n++]=p[i];
            s[n++]=0;SA_init();n--;height_init();st_init();
            int ans=0;
            for(int i=0;i<n-2*m;i++){
                int cnt=0;
                for(int j=0;j<m&&cnt<=3;){
                    if(s[i+j]!=s[n-m+j])cnt++,j++;
                    else j+=lcp(i+j,n-m+j);
                }
                if(cnt<=3)ans++;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    [JSOI2007][BZOJ1031] 字符加密Cipher|后缀数组
    leetcode Flatten Binary Tree to Linked List
    leetcode Pascal's Triangle
    leetcode Triangle
    leetcode Valid Palindrome
    leetcode Word Ladder
    leetcode Longest Consecutive Sequence
    leetcode Sum Root to Leaf Numbers
    leetcode Clone Graph
    leetcode Evaluate Reverse Polish Notation
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9199256.html
Copyright © 2011-2022 走看看