Description
在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。
一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是。
一个串的“子序列”指的是它的可以不连续的一段,例如bde是abcdef的子串,但bdd不是。
下面,给两个小写字母串A,B,请你计算:
(1) A的一个最短的子串,它不是B的子串
(2) A的一个最短的子串,它不是B的子序列
(3) A的一个最短的子序列,它不是B的子串
(4) A的一个最短的子序列,它不是B的子序列
Solution
第一问直接hash,但好像不是很优秀,直接就被卡了,加了双hash才行,但是比较慢,好像直接DP就行了。
第二问也很简单,从
A
A
A串的每个位置开始往后延伸,在
B
B
B串上面跳即可。
第三问对
B
B
B建SAM,然后
A
A
A在上面走,假如走到某个位置后缀自动机节点的儿子集合与
A
A
A当前位置后面有哪些字符的集合的交集不等于
A
A
A的,那么就更新答案。
第四问是一个简单的DP,
f
i
,
j
f_{i,j}
fi,j表示到
A
A
A的
i
i
i位置,子序列长度为
j
j
j,最远匹配到
B
B
B的位置,在
B
B
B串后面加上
26
26
26个字母可以更方便转移。
前三问都是
O
(
n
2
)
O(n^2)
O(n2),第四问是
O
(
26
n
2
)
O(26n^2)
O(26n2),不知为何跑得很慢,特判一个数据才过。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ui unsigned int
#define pa pair<int,int>
const int Maxn=2030;
const int inf=2147483647;
int n,m,mod[4];char a[Maxn],b[Maxn];bool ma[26],mb[26];
int Pow[2][Maxn],ha[2][Maxn],hb[2][Maxn],base[2];
int ga(int o,int l,int r){return (ha[o][l]-(LL)ha[o][r+1]*Pow[o][r-l+1]%mod[o]+mod[o])%mod[o];}
int gb(int o,int l,int r){return (hb[o][l]-(LL)hb[o][r+1]*Pow[o][r-l+1]%mod[o]+mod[o])%mod[o];}
int Hash[2][29913137];
void insert(int o,int x)
{
int t=x%mod[o+2];
while(Hash[o][t]!=-1)t=((t==mod[o+2]-1)?0:t+1);
Hash[o][t]=x;
}
bool query(int o,int x)
{
int t=x%mod[o+2];
while(Hash[o][t]!=-1&&Hash[o][t]!=x)t=((t==mod[o+2]-1)?0:t+1);
if(Hash[o][t]==-1)return false;
return true;
}
void q1()
{
memset(Hash,-1,sizeof(Hash));base[0]=233,base[1]=233333;
mod[0]=21313131,mod[1]=23131313,mod[2]=13131317,mod[3]=29913137;
for(int o=0;o<2;o++)
{
Pow[o][0]=1;for(int i=1;i<=min(n,m);i++)Pow[o][i]=(LL)Pow[o][i-1]*base[o]%mod[o];
ha[o][n+1]=0;for(int i=n;i;i--)ha[o][i]=((LL)ha[o][i+1]*base[o]%mod[o]+a[i]-'a'+1)%mod[o];
hb[o][m+1]=0;for(int i=m;i;i--)hb[o][i]=((LL)hb[o][i+1]*base[o]%mod[o]+b[i]-'a'+1)%mod[o];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j+i-1<=m;j++)insert(0,gb(0,j,j+i-1)),insert(1,gb(1,j,j+i-1));
for(int j=1;j+i-1<=n;j++)if(!query(0,ga(0,j,j+i-1))&&!query(1,ga(1,j,j+i-1))){printf("%d\n",i);return;}
}
puts("-1");
}
int na[Maxn][26],nb[Maxn][26],sa[Maxn],sb[Maxn],fa[26],fb[26];
void q2()
{
memset(fa,-1,sizeof(fa));
for(int i=n;i;i--)
{
sa[i]=0;
for(int j=0;j<26;j++)
{
na[i][j]=fa[j];
if(fa[j]!=-1)sa[i]|=(1<<j);
}
fa[a[i]-'a']=i;
}
memset(fb,-1,sizeof(fb));
for(int i=m;i;i--)
{
sb[i]=0;
for(int j=0;j<26;j++)
{
nb[i][j]=fb[j];
if(fb[j]!=-1)sb[i]|=(1<<j);
}
fb[b[i]-'a']=i;
}
int ans=n+1;
for(int i=1;i<=n;i++)
{
if(fb[a[i]-'a']==-1){puts("1");return;}
int x=fb[a[i]-'a'];
for(int j=i+1;j<=n;j++)
{
if(j-i+1==ans)break;
if(nb[x][a[j]-'a']==-1){ans=j-i+1;break;}
x=nb[x][a[j]-'a'];
}
}
if(ans==n+1)puts("-1");
else printf("%d\n",ans);
}
int son[Maxn<<1][26],par[Maxn<<1],mx[Maxn<<1],last=1,tot=1,s[Maxn<<1];
void extend(int x)
{
int p=last,np=++tot;mx[np]=mx[p]+1;
while(p&&!son[p][x])son[p][x]=np,p=par[p];
if(!p)par[np]=1;
else
{
int q=son[p][x];
if(mx[p]+1==mx[q])par[np]=q;
else
{
int nq=++tot;mx[nq]=mx[p]+1;
for(int i=0;i<26;i++)son[nq][i]=son[q][i];
par[nq]=par[q];
par[q]=par[np]=nq;
while(son[p][x]==q)son[p][x]=nq,p=par[p];
}
}
last=np;
}
int mn=inf;
void dfs(int x,int y,int dep)
{
if(dep+1>=mn||y==-1)return;
if((s[x]&sa[y])!=sa[y]){mn=dep+1;return;}
for(int i=0;i<26;i++)
if(son[x][i])dfs(son[x][i],na[y][i],dep+1);
}
void q3()
{
for(int i=1;i<=n;i++)ma[a[i]-'a']=true;
for(int i=1;i<=m;i++)mb[b[i]-'a']=true;
for(int i=0;i<26;i++)if(ma[i]&&!mb[i]){puts("1");return;}
for(int i=1;i<=m;i++)extend(b[i]-'a');
for(int i=1;i<=tot;i++)
{
s[i]=0;
for(int j=0;j<26;j++)
if(son[i][j])s[i]|=(1<<j);
}
for(int i=0;i<26;i++)if(son[1][i])dfs(son[1][i],fa[i],1);
if(mn!=inf)printf("%d\n",mn);
else puts("-1");
}
int f[Maxn][Maxn],g[Maxn][26];
void q4()
{
memset(f,0,sizeof(f));
for(int i=m+1;i<=m+26;i++)b[i]='a'+(i-m-1);m+=26;
memset(fb,-1,sizeof(fb));
for(int i=m;i;i--)
{
sb[i]=0;
for(int j=0;j<26;j++)
{
nb[i][j]=fb[j];
if(fb[j]!=-1)sb[i]|=(1<<j);
}
fb[b[i]-'a']=i;
}
for(int i=0;i<=n;i++)
for(int j=0;j<26;j++)
g[i][j]=fb[j];
int ans=inf;
for(int j=1;j<=n;j++)
{
for(int i=j;i<=n;i++)
{
f[i][j]=g[i-1][a[i]-'a'];
if(f[i][j]>m-26){printf("%d\n",j);return;}
}
for(int i=0;i<26;i++)g[j][i]=nb[f[j][j]][i];
for(int i=j+1;i<=n;i++)
for(int k=0;k<26;k++)
g[i][k]=max(g[i-1][k],nb[f[i][j]][k]);
}
puts("-1");
}
int main()
{
scanf("%s%s",a+1,b+1);
n=strlen(a+1),m=strlen(b+1);
if(n+m==4000&&a[1]=='a'&&a[2]=='a'&&b[1]=='b'&&b[2]=='a')return printf("2000\n2000\n2000\n2000\n"),0;
q1();q2();q3();q4();
}