P4112 [HEOI2015] 最短不公共子串

P4112 [HEOI2015] 最短不公共子串

题目描述

在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。

下面给出一些定义:

  • 一个串的“子串”指的是它的连续的一段,例如 bcdabcdef 的子串,但 bde 不是。
  • 一个串的“子序列”指的是它的可以不连续的一段,例如 bdeabcdef 的子串,但 bdd 不是。

下面,给两个小写字母串 \(a, b\),请你计算:

  1. \(a\) 的一个最短的子串,它不是 \(b\) 的子串。
  2. \(a\) 的一个最短的子串,它不是 \(b\) 的子序列。
  3. \(a\) 的一个最短的子序列,它不是 \(b\) 的子串。
  4. \(a\) 的一个最短的子序列,它不是 \(b\) 的子序列。

数据规模与约定

  • 对于 \(100\%\) 的数据,保证 \(a\)\(b\) 的长度都不超过 \(2000\)

Solution:

首先,我们不仅要构造后缀自动机,还要构造一个叫做序列自动机的东西,构造方法也十分简单,我们只需要记录每个字符最后一次出现的位置 \(last_c\) 每次插入一个的时候枚举所有字符 \(p=last_i\) ,然后不断的跳 \(p=fa_p\) 直到其出现过 \(ch[p][c]\)

然后在这两个自动机上面同步跑 bfs 就好了,至于四遍分别这么跑详见代码。

Code:

#include<bits/stdc++.h>
const int N=4005;
using namespace std;
struct SAM{
    int ch[N][26],fa[N],len[N];
    int last,cnt;
    void init(){last=cnt=1;}
    void insert(int c)
    {
        int p=last,q=++cnt;last=q;len[q]=len[p]+1;
        for(;p&&!ch[p][c];p=fa[p])ch[p][c]=q;
        if(!p){fa[q]=1;return ;}int x=ch[p][c];
        if(len[x]==len[p]+1){fa[q]=x;return ;}
        int y=++cnt;len[y]=len[p]+1;fa[y]=fa[x];
        for(int i=0;i<26;i++)ch[y][i]=ch[x][i];
        fa[x]=fa[q]=y;
        for(;p&&ch[p][c]==x;p=fa[p])ch[p][c]=y;
    }
}SA,SB;
struct SQM{
    int ch[N][26],fa[N],last[26];
    int cnt;
    void init(){cnt=1;for(int i=0;i<26;i++)last[i]=1;}
    void insert(int c)
    {
        int p=last[c],q=++cnt;fa[q]=p;
        for(int i=0;i<26;i++)for(int x=last[i];x&&!ch[x][c];x=fa[x])
        ch[x][c]=q;
        last[c]=q;
    }
}SQA,SQB;
struct Node{
    int x,y,len;
};
int vis[N][N];
int bfs(int opt)
{
    queue<Node> Q;
    Q.push({1,1,0});
    vis[1][1]=opt;
    while(!Q.empty())
    {
        int x=Q.front().x,y=Q.front().y,len=Q.front().len;Q.pop();
        for(int i=0,xx,yy;i<26;i++)
        {
            xx=(opt<=2 ? SA.ch[x][i] : SQA.ch[x][i]),yy=(opt&1? SB.ch[y][i] : SQB.ch[y][i]);
            if(xx&&yy)
            {

                if(vis[xx][yy]==opt)continue;
                //if(opt==2)cout<<char(i+'a')<<" "<<x<<" "<<y<<":"<<xx<<" "<<yy<<" "<<len+1<<"\n";
                vis[xx][yy]=opt;
                Q.push({xx,yy,len+1});
            }
            if(xx&&!yy) return len+1;
        }

    }
    return -1;
}
int n,m;
char A[N],B[N];
int ans[5];
void work()
{
    scanf("%s%s",A+1,B+1);
    n=strlen(A+1);m=strlen(B+1);
    SA.init(),SB.init(),SQA.init(),SQB.init();
    for(int i=1;i<=n;i++)SA.insert(A[i]-'a'),SQA.insert(A[i]-'a');
    for(int i=1;i<=m;i++)SB.insert(B[i]-'a'),SQB.insert(B[i]-'a');
    ans[1]=bfs(1);ans[2]=bfs(2);ans[3]=bfs(3),ans[4]=bfs(4);
    for(int i=1;i<=4;i++)printf("%d\n",ans[i]);
}
int main()
{
    //freopen("sus.in","r",stdin);freopen("sus.out","w",stdout);
    work();
    return 0;
}
posted @ 2025-01-24 16:22  liuboom  阅读(11)  评论(0)    收藏  举报