[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;
	}
}
原文地址:https://www.cnblogs.com/mollnn/p/11770758.html