BZOJ 4032: [HEOI2015]最短不公共子串(后缀自动机+记忆化搜索)

传送门

解题思路

  首先需要预处理两个串\(nxt(i)(j)\)表示i位置之后最近的\(j\)
  第一问直接对\(b\)建后缀自动机,枚举\(a\)的起点暴力匹配。
  第二问枚举\(a\)的起点,\(b\)\(nxt\)跳。
  第三问\(a\)\(b\)一起跳,\(b\)用后缀自动机,\(a\)\(nxt\)
  第四问\(a\)\(b\)一起跳,都用\(nxt\),要加记忆化。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=2005;

inline int min(int x,int y) {return x<y?x:y;}

int lena,lenb,ans=1e9,nxta[N][27],prea[27],nxtb[N][27],preb[27];
int vis[N][N];
char A[N],B[N];

struct SAM{
    int lst,cnt,fa[N<<1],ch[N<<1][27],l[N<<1];
    inline void insert(int c){
        int p=lst,np=++cnt; lst=cnt; l[np]=l[p]+1;
        for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
        if(!p) fa[np]=1;
        else {
            int q=ch[p][c];
            if(l[q]==l[p]+1) fa[np]=q;
            else {
                int nq=++cnt; l[nq]=l[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[nq]=fa[q]; fa[q]=fa[np]=nq;
                for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
    }
    inline int query1(int x){
        int p=1,ret=0;
        for(int i=x;i<=lena;i++) {
            if(ch[p][A[i]-'a']) p=ch[p][A[i]-'a'],ret++;
            else return ret+1;  
        }
        return 1e9;
    }
    inline void query3(int x,int y,int l){
        for(int i=0;i<26;i++){
            if(!ch[y][i] && nxta[x][i]) ans=min(ans,l);
            else if(ch[y][i] && nxta[x][i]) query3(nxta[x][i],ch[y][i],l+1);
        }
    }
}sam;

inline int query2(int x){
    int now=0,ret=0;
    for(int i=x;i<=lena;i++){
        if(!nxtb[now][A[i]-'a']) return ret+1;
        ret++; now=nxtb[now][A[i]-'a'];
    }
    return 1e9;
}

int query4(int x,int y){
    if(x && !y) return 1;
    if(vis[x][y]) return vis[x][y];
    int tmp=1e9;
    for(int i=0;i<26;i++){
        if(!nxta[x][i]) continue;
        tmp=min(tmp,query4(nxta[x][i],nxtb[y][i]));
    }
    vis[x][y]=tmp+1;
    return vis[x][y];
}

int main(){
    scanf("%s%s",A+1,B+1); sam.cnt=sam.lst=1;
    lena=strlen(A+1); lenb=strlen(B+1);
    for(int i=lena;~i;i--) {
        for(int j=0;j<26;j++) nxta[i][j]=prea[j];
        prea[A[i]-'a']=i; 
    }
    for(int i=lenb;~i;i--){
        for(int j=0;j<26;j++) nxtb[i][j]=preb[j];
        preb[B[i]-'a']=i;
    }   
    for(int i=1;i<=lenb;i++) sam.insert(B[i]-'a');
    for(int i=1;i<=lena;i++) ans=min(ans,sam.query1(i));
    printf("%d\n",(ans==1e9)?-1:ans); ans=1e9;
    for(int i=1;i<=lena;i++) ans=min(ans,query2(i));
    printf("%d\n",(ans==1e9)?-1:ans); ans=1e9; sam.query3(0,1,0);
    printf("%d\n",(ans==1e9)?-1:ans+1); ans=query4(0,0)-1;
    printf("%d\n",(ans==1e9)?-1:ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sdfzsyq/p/10290924.html
今日推荐