其他分享
首页 > 其他分享> > [TJOI2017] DNA - 后缀数组,稀疏表

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

作者:互联网

[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