NKOJ 4022(HEOI 2015)最短不公共子串(後綴自動機+序列自動機+dp)

P4022 [HEOI2015]最短不公共子串

問題描述

在虐各種最長公共子串、子序列的題虐的不耐煩了之後,你決定反其道而行之。

一個串的“子串”指的是它的連續的一段,例如bcd是abcdef的子串,但bde不是。

一個串的“子序列”指的是它的可以不連續的一段,例如bde是abcdef的子串,但bdd不是。

下面,給兩個小寫字母串A,B,請你計算:

(1) A的一個最短的子串,它不是B的子串

(2) A的一個最短的子串,它不是B的子序列

(3) A的一個最短的子序列,它不是B的子串

(4) A的一個最短的子序列,它不是B的子序列

輸入格式

有兩行,每行一個小寫字母組成的字符串,分別代表A和B。

輸出格式

輸出4行,每行一個整數,表示以上4個問題的答案的長度。如果沒有符合要求的答案,輸出-1.

樣例輸入

aabbcc
abcabc

樣例輸出

2
4
2
4

提示

對於100%的數據,A和B的長度都不超過2000


此題涉及到子串和子序列,考慮後綴自動機和序列自動機。
那麼此題就是在兩個自動機上dp。
對於第一問,令F1[x][y] 表示從A的後綴自動機上x節點,B的後綴自動機上y節點出發的最短不公共子串長度,那麼當x0,y=0F1[x][y]=0 ,然後直接在兩個自動機上轉移就行了,F1[x][y]=min(F1[tx][ty]+1)
對於第二問,在A的後綴自動機和B的序列自動機上同樣dp即可。
對於第三問,在A的序列自動機和B的後綴自動機上同樣dp即可。
對於第四問,在A的序列自動機和B的序列自動機上同樣dp即可。

複雜度O(26n2)?


代碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 4005
using namespace std;
struct PAM
{
    int tot,rt,las[26],pre[N],son[N][26];
    PAM()
    {
        tot=rt=1;
        for(int i=0;i<26;i++)las[i]=1;
    }
    void Ins(int c)
    {
        tot++;pre[tot]=las[c];
        for(int i=0;i<26;i++)
        for(int j=las[i];j&&!son[j][c];j=pre[j])son[j][c]=tot;
        las[c]=tot;
    }
}PA,PB;
struct SAM
{
    int rt,tot,las,son[N][26],Max[N],pra[N];
    SAM(){tot=las=rt=1;}
    int NP(int x)
    {
        Max[++tot]=x;
        return tot;
    }
    void Ins(int t)
    {
        int p=las,q,np,nq;
        np=NP(Max[p]+1);
        while(p&&!son[p][t])son[p][t]=np,p=pra[p];
        if(!p)pra[np]=rt;
        else
        {
            q=son[p][t];
            if(Max[q]==Max[p]+1)pra[np]=q;
            else
            {
                nq=NP(Max[p]+1);
                memcpy(son[nq],son[q],sizeof(son[q]));
                pra[nq]=pra[q];
                pra[q]=pra[np]=nq;
                while(son[p][t]==q)son[p][t]=nq,p=pra[p];
            }
        }
        las=np;
    }
}SA,SB;
char s1[N],s2[N];
int n,m,ans;
int F1[N][N],F2[N][N>>1],F3[N>>1][N],F4[N>>1][N>>1];
int DFS1(int x,int y)
{
    if(x&&y==0)return 0;
    if(!x||!y)return 1e9;
    if(F1[x][y]!=-1)return F1[x][y];
    F1[x][y]=1e9;
    for(int i=0;i<26;i++)F1[x][y]=min(F1[x][y],DFS1(SA.son[x][i],SB.son[y][i])+1);
    return F1[x][y];
}
int DFS2(int x,int y)
{
    if(x&&y==0)return 0;
    if(!x||!y)return 1e9;
    if(F2[x][y]!=-1)return F2[x][y];
    F2[x][y]=1e9;
    for(int i=0;i<26;i++)F2[x][y]=min(F2[x][y],DFS2(SA.son[x][i],PB.son[y][i])+1);
    return F2[x][y];
}
int DFS3(int x,int y)
{
    if(x&&y==0)return 0;
    if(!x||!y)return 1e9;
    if(F3[x][y]!=-1)return F3[x][y];
    F3[x][y]=1e9;
    for(int i=0;i<26;i++)F3[x][y]=min(F3[x][y],DFS3(PA.son[x][i],SB.son[y][i])+1);
    return F3[x][y];
}
int DFS4(int x,int y)
{
    if(x&&y==0)return 0;
    if(!x||!y)return 1e9;
    if(F4[x][y]!=-1)return F4[x][y];
    F4[x][y]=1e9;
    for(int i=0;i<26;i++)F4[x][y]=min(F4[x][y],DFS4(PA.son[x][i],PB.son[y][i])+1);
    return F4[x][y];
}
int main()
{
    scanf("%s%s",&s1[1],&s2[1]);
    s1[0]=s2[0]='%';
    n=strlen(s1)-1;
    m=strlen(s2)-1;
    for(int i=1;i<=n;i++)PA.Ins(s1[i]-'a'),SA.Ins(s1[i]-'a');
    for(int i=1;i<=m;i++)PB.Ins(s2[i]-'a'),SB.Ins(s2[i]-'a');
    memset(F1,-1,sizeof(F1));
    memset(F2,-1,sizeof(F2));
    memset(F3,-1,sizeof(F3));
    memset(F4,-1,sizeof(F4));
    ans=DFS1(1,1);printf("%d\n",ans==1e9?-1:ans);
    ans=DFS2(1,1);printf("%d\n",ans==1e9?-1:ans);
    ans=DFS3(1,1);printf("%d\n",ans==1e9?-1:ans);
    ans=DFS4(1,1);printf("%d\n",ans==1e9?-1:ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章