链接:
#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/45313429");
}
题解:
T1:
我们按长度bfs所有的串,对于每个串记录A串中终点位置、B串中终点位置(B串中位置由B的后缀自动机中节点标号表示)、长度——
(x,y,l)
。
然后
(x,y,l)
可以
O(1)
转移到
(x+1,son[y,stringax+1−′a′],l+1)
时间复杂度
O(n2)
T2:
我们记录
prex,i
表示 位置
x
之后第一个字母
然后
(x,y,l)
可以
O(1)
转移到
(x+1,pre[y,stringax+1−′a′],l+1)
时间复杂度
O(n2)
T3:
我们发现对于有相同
(x,y)
的
(x,y,l)
只取一个
l
最小的就好啦,因为对于
枚举子序列的方法是每个节点都可以枚举它后面还有哪些字母,
然后
(x,y,l)
可以
O(1)
转移到
(pre[x,?],son[y,?],l+1)
所以可以判断去重。
时间复杂度
O(n2)
有
26
的常数。
T4:
把前面的略结合一下就好啦~
然后
(x,y,l)
可以
O(1)
转移到
(pre[x,?],preB[y,?],l+1)
时间复杂度
O(n2)
有
26
的常数。
-
另外前两问也可以用判断去重的方法。
另外要注意去重的这个东西需要开 [N][N<<1]
代码:
真是悲伤的故事……
我优化了一下我的常数,结果它慢了将近一半……
400ms
→
552ms
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 2020
#define T 26
using namespace std;
struct SAM
{
int son[N<<1][T],dep[N<<1],pa[N<<1],last,cnt;
void init(){last=cnt=1;}
int newnode(int p){dep[++cnt]=dep[p]+1;return cnt;}
void add(int x)
{
int p=last;
int np=newnode(p);
while(p&&son[p][x]==0)son[p][x]=np,p=pa[p];
if(!p)pa[np]=1;
else {
int q=son[p][x];
if(dep[q]==dep[p]+1)pa[np]=q;
else {
int nq=newnode(p);
pa[nq]=pa[q],pa[q]=pa[np]=nq;
memcpy(son[nq],son[q],sizeof son[q]);
while(p&&son[p][x]==q)son[p][x]=nq,p=pa[p];
}
}
last=np;
}
void print()
{
for(int i=1;i<=30;i++)
{
for(int j=0;j<T;j++)if(son[i][j])
printf("%d %d\n",i,son[i][j]);
}
}
}sam;
char s[N],t[N];
int pre1[N][T],pre2[N][T],n,m;
struct Eli
{
int x,y,z;
Eli(int _x=0,int _y=0,int _z=0):x(_x),y(_y),z(_z){}
};
int vis[N][N<<1];
queue<Eli>q;
int getans(int f)
{
int i,x,y;
Eli U;
while(!q.empty())q.pop();
if(f<3)
{
U.z=0;
if(f==1)U.y=1;
else U.y=0;
for(i=0;i<n;i++)
{
U.x=i;
q.push(U);
}
while(!q.empty())
{
U=q.front(),q.pop();
x=U.x+1,y=s[x]-'a';
if(x>n)continue;
if(f==1)y=sam.son[U.y][y];
else y=pre2[U.y][y];
if(!y)return U.z+1;
else if(vis[x][y]!=f)
{
vis[x][y]=f;
q.push(Eli(x,y,U.z+1));
}
}
}
else if(f==3)
{
q.push(Eli(0,1,0));
while(!q.empty())
{
U=q.front(),q.pop();
for(i=0;i<T;i++)if(x=pre1[U.x][i])
{
y=sam.son[U.y][i];
if(!y)return U.z+1;
else if(vis[x][y]!=f)
{
vis[x][y]=f;
q.push(Eli(x,y,U.z+1));
}
}
}
}
else {
q.push(Eli(0,0,0));
while(!q.empty())
{
U=q.front(),q.pop();
for(i=0;i<T;i++)if(x=pre1[U.x][i])
{
y=pre2[U.y][i];
if(!y)return U.z+1;
else if(vis[x][y]!=f)
{
vis[x][y]=f;
q.push(Eli(x,y,U.z+1));
}
}
}
}
return -1;
}
int main()
{
int i,j,k;
scanf("%s%s",s+1,t+1);
n=strlen(s+1),m=strlen(t+1);
sam.init();
for(i=1;i<=m;i++)sam.add(t[i]-'a');
for(i=n-1;~i;i--)
{
memcpy(pre1[i],pre1[i+1],sizeof pre1[i+1]);
pre1[i][s[i+1]-'a']=i+1;
}
for(i=m-1;~i;i--)
{
memcpy(pre2[i],pre2[i+1],sizeof pre2[i+1]);
pre2[i][t[i+1]-'a']=i+1;
}
printf("%d\n%d\n%d\n%d\n",getans(1),getans(2),getans(3),getans(4));
return 0;
}