设\(lenth_i\)为\(s\)在\(i\)位置的前缀的后缀为\(t\)的一个子串的最长长度,即为从\(i\)位置开始往前和\(t\)的最长公共子串长度。其可以通过对\(t\)建后缀自动机,然后让\(s\)在自动机上匹配来求出。

求出\(lenth_i\)后,对于区间\([l,r]\)的一个询问,其答案即为:

\[ \max_{i=l}^r \lbrace\ \min(lenth_i,i-l+1)\ \rbrace
\]

发现内层的\(\min\)不好处理,考虑将其去掉:

当\(lenth_i \leqslant i-l+1\)时,其值为\(lenth_i\),转化得\(i-lenth_i+1 \geqslant l\),发现\(i-lenth_i+1\)的值是单调不降的,因为每到下一个位置,\(i\)都会加一,而\(lenth_i\)可能加一,可能清零,所以该值是单调不降的。

那么对于区间\([l,r]\),一定存在一个位置\(pos\),满足所有\(i \geqslant pos\),都有\(i-lenth_i+1 \geqslant l\)。那么在区间\([pos,r]\)中,\(\min\)取到了\(lenth_i\),在区间\([l,pos-1]\)中,\(\min\)取到了\(i-l+1\)。

\(pos\)可以通过二分求得,然后答案即为区间\([pos,r]\)内\(lenth_i\)的最大值和\(pos-l\)取\(\max\)。

\(code:\)

#include<bits/stdc++.h>
#define maxn 400010
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int l1,l2,q,root=1,las=1,tot=1;
int len[maxn],fa[maxn],ch[maxn][2],lenth[maxn],f[maxn][25],lg[maxn];
char s[maxn],t[maxn];
void insert(int c)
{
int p=las,np=las=++tot;
len[np]=len[p]+1;
while(p&&!ch[p][c]) ch[p][c]=np,p=fa[p];
if(!p) fa[np]=root;
else
{
int q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++tot;
ch[nq][0]=ch[q][0],ch[nq][1]=ch[q][1];
len[nq]=len[p]+1,fa[nq]=fa[q],fa[q]=fa[np]=nq;
while(ch[p][c]==q) ch[p][c]=nq,p=fa[p];
}
}
}
void init()
{
lg[0]=-1;
for(int i=1;i<=l1;++i) lg[i]=lg[i>>1]+1;
for(int i=1;i<=l1;++i) f[i][0]=lenth[i];
for(int j=1;j<=20;++j)
for(int i=1;i+(1<<j)-1<=l1;++i)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int query(int l,int r)
{
if(l>r) return 0;
int len=lg[r-l+1];
return max(f[l][len],f[r-(1<<len)+1][len]);
}
int find(int l,int r)
{
int pos=r+1,L=l;
while(l<=r)
{
int mid=(l+r)>>1;
if(mid-lenth[mid]+1>=L) pos=mid,r=mid-1;
else l=mid+1;
}
return pos;
}
void work()
{
int p=root;
for(int i=1;i<=l1;++i)
{
int c=s[i]-'a';
if(ch[p][c]) lenth[i]=lenth[i-1]+1,p=ch[p][c];
else
{
while(p&&!ch[p][c]) p=fa[p];
if(!p) p=root;
else lenth[i]=len[p]+1,p=ch[p][c];
}
}
}
int main()
{
scanf("%s%s",s+1,t+1);
l1=strlen(s+1),l2=strlen(t+1);
for(int i=1;i<=l2;++i) insert(t[i]-'a');
work(),init(),read(q);
while(q--)
{
int l,r,pos;
read(l),read(r),pos=find(l,r);
printf("%d\n",max(query(pos,r),pos-l));
}
return 0;
}

最新文章

  1. 设置tomcat远程debug
  2. 如何在文章/随笔中添加可运行的js代码
  3. word嵌入图片部分被段落遮挡
  4. C2解题报告合集~
  5. C语言-L Buffer is too small &amp;&amp; 0 解决方法
  6. 最好用的手机编程软件-C4droid
  7. 关于C语言中的强符号、弱符号、强引用和弱引用的一些陋见,欢迎指正
  8. matlab读取csv文件数据并绘图
  9. 关于新写的js在浏览器f12的时候看不到解决办法
  10. Scrapy 解决Scrapy安装时报错&quot;Microsoft Visual C++ 14.0 is required&quot;
  11. Mysql5.7实现主从复制、基于GTID的主从复制、并行复制
  12. bootstrap 模态 modal 小例子【转】
  13. Node内核基本自带模块fs 文件的读写
  14. Python中Flask框架SQLALCHEMY_ECHO设置
  15. bzoj2464 小明的游戏
  16. iOS 网络请求数据缓存
  17. ClamAV资料链接
  18. Win10双网卡不双待攻略
  19. SQL Server -&gt;&gt; 高可用与灾难恢复(HADR)技术之 -- Windows故障转移群集
  20. 【Python笔记】十分钟搞定pandas

热门文章

  1. 明文暴露___JS前台加密,java后台解密实现
  2. 几个超级实用但很少人知道的 VS 技巧
  3. 3分钟看懂C#委托
  4. 微信小程序点击保存图片到本地相册——踩坑
  5. 【转载】张一鸣:为什么 BAT 挖不走我们的人才?
  6. lsomap降维
  7. 异常重试框架Spring Retry实践
  8. python抓取头条文章
  9. 一张图片在Python操作下的4种玩法(附源码)
  10. RISC-V发展现状