题意:
分析:
- 暴力:
对于每一次询问,在t里面哈希找最长总共子串,单次复杂度(O(|t|log |t|)) ,总复杂度 (O(q|t|log |t|)),期望得分:50pts
- 正解:
对于最长公共子串问题考虑后缀字符串算法
我们发现,对于暴力做法单次查询的复杂度过高,所以考虑使用SAM进行优化,我们可以直接求出每一个i,求出最长的 (len[i]) 使得 (s[i-len[i]+1,i]) 为 t 的一个子串,那么我们的答案就是 (max{i-max(l,i-len[i]+1)+1})
对于第二个 max 我们分类讨论:
- (l> i-len[i]+1) 时 (ans=max(i-l+1))
- (lle i-len[i]+1) 时 (ans=max(len[i]))
仔细思考一下我们会发现,(i-len[i]+1) 是单调不减的,感性理解,最长公共子串的左端点只会不断右移
所以我们可以对于询问按 l 升序排序,然后双指针每次找到分界点 i,查询区间最值就可以了
tip: 树状数组查询区间最值的时候,需要一部分跳(lowbit),一部分暴力取max
代码:
#include<bits/stdc++.h>
#define inl inline
#define reg register
using namespace std;
namespace zzc
{
inl int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int maxn = 6e5+5;
int n,m,qt;
int length[maxn],ans[maxn];
char s[maxn],t[maxn];
struct que
{
int l,r,id;
bool operator <(const que &b)const
{
return l<b.l;
}
}q[maxn];
struct suffix_automaton
{
int tot,lst;
int len[maxn],trans[maxn][26],link[maxn];
suffix_automaton(){tot=lst=1;}
inl void insert(int x)
{
int cur=++tot,tmp=lst;lst=tot;
len[cur]=len[tmp]+1;
for(;tmp&&!trans[tmp][x];tmp=link[tmp]) trans[tmp][x]=cur;
if(!tmp) link[cur]=1;
else
{
int q=trans[tmp][x];
if(len[tmp]+1==len[q]) link[cur]=q;
else
{
int clone=++tot;
len[clone]=len[tmp]+1;
link[clone]=link[q];
for(reg int i=0;i<=25;i++) trans[clone][i]=trans[q][i];
link[cur]=link[q]=clone;
for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone;
}
}
}
inl void build()
{
for(reg int i=1;i<=m;i++) insert(t[i]-'a');
for(reg int i=1,now=1,tmp=0;i<=n;i++)
{
while(now&&!trans[now][s[i]-'a']) now=link[now],tmp=len[now];
if(!now) now=1,tmp=0;
else now=trans[now][s[i]-'a'],tmp++;
length[i]=min(tmp,i);
}
}
}sam;
struct bit
{
int c[maxn];
inl int lowbit(int x) {return x&(-x);}
inl void add(int x,int k) {for(reg int i=x;i<=n;i+=lowbit(i)) c[i]=max(c[i],k);}
inl int query(int l,int r)
{
int res=0;
while(l<=r)
{
while(r-lowbit(r)>=l) res=max(res,c[r]),r-=lowbit(r);
res=max(res,length[r--]);
}
return res;
}
}tr;
void work()
{
scanf("%s",s+1);n=strlen(s+1);
scanf("%s",t+1);m=strlen(t+1);
sam.build();
for(reg int i=1;i<=n;i++) tr.add(i,length[i]);
qt=read();
for(reg int i=1;i<=qt;i++)
{
q[i].l=read();q[i].r=read();
q[i].id=i;
}
sort(q+1,q+qt+1);
for(reg int i=1,j=1,l=1;i<=n&&j<=qt;l++)
{
while(i<=n&&i-length[i]+1<l) i++;
while(j<=qt&&q[j].l==l)
{
if(i-1>=l) ans[q[j].id]=min(i-1,q[j].r)-l+1;
if(i<=q[j].r) ans[q[j].id]=max(ans[q[j].id],tr.query(max(i,l),q[j].r));
j++;
}
}
for(reg int i=1;i<=qt;i++) printf("%d
",ans[i]);
}
}
int main()
{
zzc::work();
return 0;
}