[TJOI2017]DNA——后缀数组求LCP

Posted ylsoi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[TJOI2017]DNA——后缀数组求LCP相关的知识,希望对你有一定的参考价值。

题目大意:

给定一个文本串和一个模式串,求文本串中有多少个连续的子串和模式串相差不超过三个字符。

思路:

算是一道后缀数组的模板题。

直接做lcp,然后遇到匹配不上的就跳,跳的次数不能超过三次。

具体地,将两个字符串连在一起,中间加一个分隔符,然后求出height,用rmq维护height数组的区间最小值即可。

/*=======================================
 * Author : ylsoi
 * Time : 2019.2.5
 * Problem : luogu3763
 * E-mail : [email protected]
 * ====================================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;

using namespace std;

void File(){
    freopen("luogu3763.in","r",stdin);
    freopen("luogu3763.out","w",stdout);
}

template<typename T>void read(T &_){
    _=0; T fl=1; char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
    for(;isdigit(ch);ch=getchar())_=(_<<1)+(_<<3)+(ch^'0');
    _*=fl;
}

const int maxn=2e5+10;
int T;
int n,m;
char s[maxn];
int sz,sa[maxn],tp[maxn],rk[maxn],tax[maxn],height[maxn];
int st[maxn][21],Log[maxn];

void radix_sort(){
    REP(i,1,sz)tax[i]=0;
    REP(i,1,n)++tax[rk[i]];
    REP(i,1,sz)tax[i]+=tax[i-1];
    DREP(i,n,1)sa[tax[rk[tp[i]]]--]=tp[i];
}

void suffix_sort(){
    sz=26;
    REP(i,1,n)rk[i]=s[i]-'A'+1,tp[i]=i;
    radix_sort();
    for(int w=1,p=0;w<n;w<<=1){
        p=0;
        REP(i,1,w)tp[++p]=n-w+i;
        REP(i,1,n)if(sa[i]>w)tp[++p]=sa[i]-w;
        radix_sort();
        swap(rk,tp);
        rk[sa[1]]=p=1;
        REP(i,2,n)
            if(tp[sa[i-1]]==tp[sa[i]] && tp[sa[i-1]+w]==tp[sa[i]+w])rk[sa[i]]=p;
            else rk[sa[i]]=++p;
        sz=p;
        if(sz==n)break;
    }
}

void get_height(){
    int k=0;
    REP(i,1,n){
        if(k)--k;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])++k;
        height[rk[i]]=k;
    }
}

void init_st(){
    REP(i,1,n)st[i][0]=height[i];
    REP(j,1,Log[n])REP(i,1,n-(1<<j)+1)
        st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}

int lcp(int x,int y){
    x=rk[x],y=rk[y];
    if(x>y)swap(x,y);
    ++x;
    int d=Log[y-x+1];
    return min(st[x][d],st[y-(1<<d)+1][d]);
}

int main(){
    File();
    REP(i,2,2e5)Log[i]=Log[i>>1]+1;
    read(T);
    while(T--){
        scanf("%s",s+1);
        m=strlen(s+1)+1;
        s[m]='Z';
        scanf("%s",s+m+1);
        n=strlen(s+1);
        suffix_sort();
        get_height();
        init_st();
        int ans=0;
        REP(i,1,m-n+m){
            int p=0,len;
            REP(j,1,4){
                len=lcp(i+p,m+1+p);
                p+=len;
                if(p==n-m){++ans; break;}
                else ++p;
            }
        }
        printf("%d
",ans);
    }
    return 0;
}

以上是关于[TJOI2017]DNA——后缀数组求LCP的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4892 [TJOI2017]DNA

[TJOI2017]DNA --- 后缀数组

[BZOJ4892][TJOI2017]DNA(后缀数组)

Luogu-3966 [TJOI2013]单词

[BZOJ4556][TJOI2016&&HEOI2016]字符串

bzoj4556: [Tjoi2016&Heoi2016]字符串 (后缀数组加主席树)