ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[TJOI2017] DNA - 后缀数组,稀疏表

2019-10-31 14:05:02  阅读:275  来源: 互联网

标签:DNA 匹配 后缀 st 250005 int TJOI2017 return sa


[TJOI2017] DNA

Description

求模式串与主串的匹配次数,容错不超过三个字符。

Solution

枚举每个开始位置,进行暴力匹配,直到失配次数用光或者匹配成功。考虑到容错量很小,所以每个位置开始的匹配过程中大部分与普通匹配是同样操作,而我们需要的其实就是 LCP 长度,所以预处理出后缀数组和高度数组,建 ST 表支持 RMQ 询问,来加速暴力匹配的过程。时间复杂度 \(O(n \log n)\)

#include <bits/stdc++.h>
using namespace std;

int n,k,l0,m=256,sa[250005],y[250005],u[250005],v[250005],o[250005],r[250005],h[250005],T;
char str[250005];
int lg2[250005];

struct clsst {
    int a[250005][21];
    void build(int *src,int n) {
        for(int i=1;i<=n;i++) a[i][0]=src[i];
        for(int i=1;i<=20;i++)
            for(int j=1;j<=n-(1<<i)+1;j++)
                a[j][i]=min(a[j][i-1],a[j+(1<<(i-1))][i-1]);
    }
    int query(int l,int r) {
        if(l>r) swap(l,r);
        int j=lg2[r-l+1];
        return min(a[l][j],a[r-(1<<j)+1][j]);
    }
} st;

int lcp(clsst *st,int p,int q)
{
    if(r[p]>r[q]) swap(p,q);
    return st->query(r[p]+1,r[q]);
}

int match(clsst *st,int p,int q)
{
    return lcp(st,p,l0+1+q);
}

int matchstr(clsst *st,int p,int q,int x)
{
    if(x<0) return 0;
    if(q>k-x) return 1;
    int step = match(st,p,q);
    //cout<<"matchstr "<<p<<" "<<q<<" "<<x<<" "<<step<<endl;
    p+=step-1;
    q+=step-1;
    if(q>=k-x) return 1;
    else return matchstr(st,p+2,q+2,x-1);
}

int main(){
    for(int i=1;i<=250000;i++) lg2[i]=log2(i);

    scanf("%d",&T);

    while(T--) {
        memset(sa,0,sizeof sa);
        memset(y,0,sizeof y);
        memset(u,0,sizeof u);
        memset(v,0,sizeof v);
        memset(o,0,sizeof o);
        memset(r,0,sizeof r);
        memset(h,0,sizeof h);
        memset(str,0,sizeof str);

        scanf("%s",str+1);
        n=l0=strlen(str+1);

        str[n+1]='$';

        scanf("%s",str+n+2);
        k=strlen(str+n+2);
        n+=k+1;

        for(int i=1;i<=n;i++) u[str[i]]++;
        for(int i=1;i<=m;i++) u[i]+=u[i-1];
        for(int i=n;i>=1;i--) sa[u[str[i]]--]=i;
        r[sa[1]]=1;
        for(int i=2;i<=n;i++) r[sa[i]]=r[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]);

        for(int l=1;r[sa[n]]<n;l<<=1) {
            memset(u,0,sizeof u);
            memset(v,0,sizeof v);
            memcpy(o,r,sizeof r);
            for(int i=1;i<=n;i++) u[r[i]]++, v[r[i+l]]++;
            for(int i=1;i<=n;i++) u[i]+=u[i-1], v[i]+=v[i-1];
            for(int i=n;i>=1;i--) y[v[r[i+l]]--]=i;
            for(int i=n;i>=1;i--) sa[u[r[y[i]]]--]=y[i];
            r[sa[1]]=1;
            for(int i=2;i<=n;i++) r[sa[i]]=r[sa[i-1]]+((o[sa[i]]!=o[sa[i-1]])||(o[sa[i]+l]!=o[sa[i-1]+l]));
        }
        {
            int i,j,k=0;
            for(int i=1;i<=n;h[r[i++]]=k)
                for(k?k--:0,j=sa[r[i]-1];str[i+k]==str[j+k];k++);
        }
        memset(st.a,0,sizeof st.a);
        st.build(h,n);
        int ans = 0;
        for(int i=1;i<=l0-k+1;i++)
        {
            //cout<<"try "<<i<<endl;
            int tmp = matchstr(&st,i,1,3);
            //if(tmp==1) cout<<i<<endl;
            ans += tmp;
        }
        cout<<ans<<endl;
    }
}

标签:DNA,匹配,后缀,st,250005,int,TJOI2017,return,sa
来源: https://www.cnblogs.com/mollnn/p/11770758.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有