Description
小
ω
有很多字符串,它们都由小写字母构成。
给你
n
个字符串
a
i
,和
Q
个询问,每次对两个串
S
=
a
i
, T
=
a
j
询问最大的
L
(0
≤
L
≤ |
S
|
)
使得
S
[
n n L
+ 1
. . .
|
S
|
] =
T
[1
. . . L
]
。
Input
从文件
string.in
中读入数据。
第一行两个正整数
n, Q
,表示一共有
n
个字符串,以及有
Q
个询问。
下面
n
行,每行一个字符串
a
i
。
下面
Q
行,每行两个正整数
x, y
,表示询问
S
=
a
x
和
T
=
a
y
。
Output
输出到文件
string.out
中。
输出
Q
行,每行一个非负整数,表示最大的
L
。
Sample input
3 6
wwq
eew
qwe
1 2
2 3
1 3
2 1
3 2
3 1
Sample Output
0
0
1
1
1
0
【样例
2
】
见选手目录下的
string/string2.in
与
string/string2.ans
。
该样例满足第二档部分分的性质。
【样例
3
】
见选手目录下的
string/string3.in
与
string/string3.ans
。
该样例满足第三档部分分的性质。
【样例
4
】
见选手目录下的
string/string4.in
与
string/string4.ans
。
该样例满足第四档部分分的性质。
Data Constraint
Solutoin
对于每一个字符串处理出其字符串哈希值。
暴力扫描即可,对于n<200的直接记录答案。
法一:
对于小于根号L的直接暴力求,对于大于根号L的只有少于根号L个,记录下来。
时间复杂度O(QL^{1/2})
对于长度大于等于 √ L 的只有 O( √ L) 个,处理它们两两之间答案。 否则只要存在一个长度小于 √ L 的,就可以直接 O( √ L) 比较。 复杂度 O((L + Q) √ L),期望得分 70 ∼ 100。 3 调一下块大小能够做到 O(L √ Q)。 由于出题人忘记造到 trie 上了,没有体现更好的区分度在此谢罪。
法二:
如果把所有串建出 AC 自动机。设 B 满足 S = S ′ + B,T = B + T ′,则 S 在 fail 树上到祖先链里恰好有 B。 我们要最大化这个 B,其实是要求 trie 树上根到 T 的链,与 fail 树上,根到 S 的链,并的深度最大的节点。 将问题离线,在 trie 上 dfs,每次把当前点的信息加入数据结构,dfs 到 T 处 时查询 S 处的答案。 直接使用树链剖分,时间复杂度 O(n log2 n),期望得分 70 ∼ 100。 考虑我们的操作只是子树 max,单点查询,考虑标记永久化后使用可回退数据 结构。时间复杂度 O(n log n),期望得分 100。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#define I int
#define llu unsigned long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define N 600060
using namespace std;
char s[N],c;
I n,Q,x,y,ans,len,st[N],ed[N],bz[5020][5020];
llu pre[N],suf[N],p=131,now;
I R(I &x){
x=0;I w=1;c=getchar();
while(c<'0'||c>'9'){if(c=='-') w=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*=w;
}
I pd(){return suf[ed[x]-ans+1]==pre[st[y]+ans-1];}
I main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
R(n),R(Q);
F(i,1,n){
c=getchar();
while(c<'a'||c>'z') c=getchar();
while(c>='a'&&c<='z'){
s[++len]=c;
c=getchar();
}
st[i]=ed[i-1]+1,ed[i]=len;
pre[st[i]]=s[st[i]]-'a'+1;
F(j,st[i]+1,ed[i]) pre[j]=pre[j-1]*p+s[j]-'a'+1;
suf[ed[i]]=s[ed[i]]-'a'+1;now=p;
Fd(j,ed[i]-1,st[i]){suf[j]=suf[j+1]+(s[j]-'a'+1)*now;now*=p;}
}
memset(bz,255,sizeof bz);
while(Q--){
R(x),R(y);
if(x<=5000&&y<=5000&&bz[x][y]!=-1){printf("%d\n",bz[x][y]);continue;}
ans=min(ed[x]-st[x]+1,ed[y]-st[y]+1);
while(!pd()&&ans) ans--;
printf("%d\n",ans);
if(x<=5000&&y<=5000) bz[x][y]=ans;
}
return 0;
}