Description
在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。
一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是。
一个串的“子序列”指的是它的可以不连续的一段,例如bde是abcdef的子串,但bdd不是。
下面,给两个小写字母串A,B,请你计算:
(1) A的一个最短的子串,它不是B的子串
(2) A的一个最短的子串,它不是B的子序列
(3) A的一个最短的子序列,它不是B的子串
(4) A的一个最短的子序列,它不是B的子序列
Input
有两行,每行一个小写字母组成的字符串,分别代表A和B。
Output
输出4行,每行一个整数,表示以上4个问题的答案的长度。如果没有符合要求的答案,输出-1.
Sample Input
aabbcc
abcabc
Sample Output
2
4
2
4
HINT
对于100%的数据,A和B的长度都不超过2000
我从未见过如此鬼畜的字符串DP四合一.
自己只会做前两问…果然SAM学的还是不到位…
最后膜了一发吉利跪吉利添动力
我还是想吐槽一句:
我自己的代码真TM丑!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 4100
using namespace std;
char A[MAXN],B[MAXN];
int la,lb,ans;
int F[MAXN];
int f[MAXN>>1][MAXN>>1];//Question1 DP出后缀两两间<del>SCP</del>LCP长度
int a[MAXN],change[MAXN>>1][MAXN>>1];//Question2 枚举A串起始点贪心
struct sam//Question3 对B建后缀自动机F i j表示A串中终止位置为i匹配到自动机中的第j个状态的最短长度
//Question 4 同样对B建后缀自动机+贪心
{
int p,q,np,nq,last,cnt;
int a[MAXN][26],len[MAXN],fa[MAXN];
sam()
{
last=++cnt;
}
void insert(int c)
{
p=last;np=last=++cnt;len[np]=len[p]+1;
while (!a[p][c]&&p) a[p][c]=np,p=fa[p];
if (!p) fa[np]=1;
else
{
q=a[p][c];
if (len[q]==len[p]+1) fa[np]=q;
else
{
nq=++cnt;len[nq]=len[p]+1;
memcpy(a[nq],a[q],sizeof(a[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
while (a[p][c]==q) a[p][c]=nq,p=fa[p];
}
}
}
}sam;
void print()
{
if (ans==la+1) puts("-1");
else printf("%d\n",ans);
}
int main()
{
scanf("%s",A+1);scanf("%s",B+1);A[0]='a';B[0]='a';
la=strlen(A+1);lb=strlen(B+1);ans=la+1;
for (int i=la;i;i--)
for (int j=lb;j;j--)
if (A[i]==B[j]) f[i][j]=f[i+1][j+1]+1;
for (int i=1;i<=la;i++)
{
int maxn=0;
for (int j=1;j<=lb;j++) maxn=max(maxn,f[i][j]);
if (maxn!=la-i+1) ans=min(ans,maxn+1);
}
print();ans=la+1;
for (int i=0;i<26;i++) a[i]=la+1;
for (int i=lb;i>=0;i--)
{
for (int j=0;j<26;j++) change[i][j]=a[j];
a[B[i]-'a']=i;
}
for (int i=1;i<=la;i++)
{
int now=0;
for (int j=i;j<=la;j++)
{
now=change[now][A[j]-'a'];
if (now>la)
{
ans=min(ans,j-i+1);
break;
}
}
}
print();ans=la+1;int temp;
for (int i=1;i<=lb;i++) sam.insert(B[i]-'a');
memset(F,0x3f,sizeof(F));F[1]=0;
for (int i=1;i<=la;i++)
for (int j=1;j<=sam.cnt;j++)
{
if (!(temp=sam.a[j][A[i]-'a'])) ans=min(ans,F[j]+1);
else F[temp]=min(F[temp],F[j]+1);
}
print();ans=la+1;
memset(F,0x3f,sizeof(F));F[0]=0;
for (int i=1;i<=la;i++)
for (int j=lb;j>=0;j--)
{
if ((temp=change[j][A[i]-'a'])>la) ans=min(ans,F[j]+1);
else F[temp]=min(F[temp],F[j]+1);
}
print();
}