bzoj 4032 [HEOI2015]最短不公共子串——后缀自动机

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4032

不是 b 的子串的话就对 b 建后缀自动机,在 a 上枚举从每个位置开始的子串或者找子序列(子序列就是记录 a 的前 i 个,走到 b 的 j 状态用的最短长度),对应到自动机上看看能不能走下去就行了。

不是 b 的子序列的话就对 b 建子序列自动机?就是那个知道每个位置再填一个字符会走到哪个位置的数组。然后在 a 上枚举,看看自动机上能不能走下去就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2005,M=4005,K=30;
char a[N],b[N];
int n,m,cnt=1,lst=1,go[M][K],fa[M],l[M],nxt[N][K],lt[K];
int dp[N][M];//M//int
int Mn(int a,int b){return a<b?a:b;}
void add(int w)
{
  int p=lst,np=++cnt;lst=np;l[np]=l[p]+1;
  for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
  if(!p)fa[np]=1;
  else
    {
      int q=go[p][w];
      if(l[q]==l[p]+1)fa[np]=q;
      else
    {
      int nq=++cnt;l[nq]=l[p]+1;
      fa[nq]=fa[q];fa[q]=nq;fa[np]=nq;
      memcpy(go[nq],go[q],sizeof go[q]);
      for(;go[p][w]==q;p=fa[p])go[p][w]=nq;
    }
    }
}
void solve1()
{
  int ans=n+1;
  for(int i=1;i<=n;i++)
    {
      int cr=1;
      for(int j=i;j<=n;j++)
    {
      if(!go[cr][a[j]-'a'+1])
        {ans=Mn(ans,j-i+1);break;}
      cr=go[cr][a[j]-'a'+1];
    }
    }
  printf("%d\n",ans>n?-1:ans);
}
void solve2()
{
  int ans=n+1;
  for(int t=1;t<=n;t++)
    {
      int cr=0;
      for(int i=t;i<=n;i++)
    {
      int d=a[i]-'a'+1;
      if(nxt[cr][d])cr=nxt[cr][d];
      else {ans=Mn(ans,i-t+1);break;}
    }
    }
  printf("%d\n",ans>n?-1:ans);
}
void solve3()
{
  memset(dp,0x3f,sizeof dp);
  dp[0][1]=0; int ans=n+1;
  for(int i=1;i<=n;i++)
    {
      int d=a[i]-'a'+1;
      for(int j=1;j<=cnt;j++)
    if(dp[i-1][j]<=n)
    {
      dp[i][j]=Mn(dp[i][j],dp[i-1][j]);
      if(!go[j][d])ans=Mn(ans,dp[i-1][j]+1);
      else dp[i][go[j][d]]=Mn(dp[i][go[j][d]],dp[i-1][j]+1);
    }
    }
  printf("%d\n",ans>n?-1:ans);
}
void solve4()
{
  memset(dp,0x3f,sizeof dp);
  dp[0][0]=0; int ans=n+1;
  for(int i=1;i<=n;i++)
    {
      int d=a[i]-'a'+1;
      for(int j=0;j<=m;j++)
    if(dp[i-1][j]<=n)
      {
        dp[i][j]=Mn(dp[i][j],dp[i-1][j]);
        if(!nxt[j][d])ans=Mn(ans,dp[i-1][j]+1);
        else dp[i][nxt[j][d]]=Mn(dp[i][nxt[j][d]],dp[i-1][j]+1);
      }
    }
  printf("%d\n",ans>n?-1:ans);
}
int main()
{
  scanf("%s",a+1);scanf("%s",b+1);
  n=strlen(a+1);m=strlen(b+1);
  for(int i=1;i<=m;i++)add(b[i]-'a'+1);
  for(int i=m;i>=0;i--)
    {
      for(int j=1;j<=26;j++)
    nxt[i][j]=lt[j];
      lt[b[i]-'a'+1]=i;
    }
  solve1();solve2();
  solve3();solve4();
  return 0;
}

 

posted on 2018-12-12 14:30  Narh  阅读(169)  评论(0编辑  收藏  举报

导航