洛谷P6640/LOJ#3298[BJOI2020]封印
口胡一发。
把 $s,t$ 扔一起建后缀数组,扫描线一下得出 $s$ 的每一个后缀和 $t$ 的 LCP 长度(以第 $i$ 个字符开始的记为 $lcp_i$),然后答案就是 $\max\limits^r_{i=l}\min(lcp_i,r-i+1)$,显然离线一下,根据 $i+lcp_i$ 和 $r+1$ 的大小关系分类,拿线段树扫一下即可。
时间复杂度 $O((|s|+|t|+q)\log(|s|+|t|))$。
代码:
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> #include<utility> #include<numeric> #define For(i,A,B) for(i=(A);i<=(B);++i) #define Ford(i,B,A) for(i=(B);i>=(A);--i) #define fi first #define se second using namespace std; typedef pair<int,int> pii; const int N=200050; const int BUF=1<<21; char rB[BUF],*rS,*rT,wB[BUF+50],*wT=wB; inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,BUF,stdin),rS==rT)?EOF:*rS++;} inline void flush(){fwrite(wB,1,wT-wB,stdout);wT=wB;} inline int rdi(){ char c=gc(); while(!isdigit(c))c=gc(); int x=c&15; for(c=gc();isdigit(c);c=gc())x=x*10+(c&15); return x; } inline void rds(char*s){ char c=gc(); while(!islower(c))c=gc(); *s++=c; while(islower(c=gc()))*s++=c; *s='\0'; } short buf[15]; inline void wt(int x){ short l=-1; if(wT-wB>BUF)flush(); while(x>9){ buf[++l]=x%10; x/=10; } *wT++=x|48; while(l>=0)*wT++=buf[l--]|48; *wT++='\n'; } char s[N*2]; int sa[N*2],t1[N*4],t2[N*4],c[N*2],rnk[N*2],h[N*2],maxn[N*4],ps[N],l[N],r[N],tr[N],ans[N]; pii lcp[N]; inline bool cmppii(const pii&a,const pii&b){return a.fi+a.se<b.fi+b.se;} inline bool cmpi(int x,int y){return r[x]<r[y];} inline void chkmin(int&a,int b){if(b<a)a=b;} inline void chkmax(int&a,int b){if(a<b)a=b;} void build(int o,int L,int R){ if(L==R)ps[L]=o; else{ int M=L+R>>1; build(o*2,L,M); build(o*2|1,M+1,R); } } inline void ins(int x,int k){ for(int o=ps[x];o;o>>=1)chkmax(maxn[o],k); } int query(int o,int L,int R,int x,int y){ if(x<=L&&y>=R)return maxn[o]; int M=L+R>>1,ans=~0x3f3f3f3f; if(x<=M)ans=query(o*2,L,M,x,y); if(y>M)chkmax(ans,query(o*2|1,M+1,R,x,y)); return ans; } int main(){ int n,m,q,p=3,i,j,k,*x=t1,*y=t2,res; rds(s+1);n=strlen(s+1); s[n+1]='c'; rds(s+n+2);m=strlen(s+n+2); For(i,1,n+m+1)++c[x[i]=s[i]-'a'+1]; partial_sum(c+1,c+p+1,c+1); Ford(i,n+m+1,1)sa[c[x[i]]--]=i; for(k=1;k<=n+m;k<<=1){ j=0; Ford(i,n+m+1,n+m-k+2)y[++j]=i; For(i,1,n+m+1)if(sa[i]>k)y[++j]=sa[i]-k; memset(c,0,sizeof(c)); For(i,1,n+m+1)++c[x[i]]; partial_sum(c+1,c+p+1,c+1); Ford(i,n+m+1,1)sa[c[x[y[i]]]--]=y[i]; swap(x,y); p=1; For(i,1,n+m+1)x[sa[i]]=y[sa[i]]==y[sa[i+1]]&&y[sa[i]+k]==y[sa[i+1]+k]?p:p++; if(p>n+m+1)break; } For(i,1,n+m+1)rnk[sa[i]]=i; j=0; For(i,1,n+m+1)if(rnk[i]<=n+m){ if(j)--j; while(s[i+j]==s[sa[rnk[i]+1]+j])++j; h[rnk[i]]=j; } res=0; For(i,1,n+m+1)if(sa[i]>n+1)res=h[i]; else{ if(sa[i]<=n)lcp[sa[i]].se=res; chkmin(res,h[i]); } res=0; Ford(i,n+m+1,1)if(sa[i]>n+1)res=h[i-1]; else{ if(sa[i]<=n)chkmax(lcp[sa[i]].se,res); chkmin(res,h[i-1]); } For(i,1,n)lcp[i].fi=i; sort(lcp+1,lcp+n+1,cmppii); build(1,1,n); iota(tr+1,tr+(q=rdi())+1,1); For(i,1,q){l[i]=rdi();r[i]=rdi();} sort(tr+1,tr+q+1,cmpi); memset(maxn,~0x3f,sizeof(maxn)); j=1; For(i,1,q){ for(;j<=n&&lcp[j].fi+lcp[j].se<=r[tr[i]];++j)ins(lcp[j].fi,lcp[j].se); ans[tr[i]]=query(1,1,n,l[tr[i]],r[tr[i]]); } memset(maxn,~0x3f,sizeof(maxn)); j=n; Ford(i,q,1){ for(;j&&lcp[j].fi+lcp[j].se>=r[tr[i]]+1;--j)ins(lcp[j].fi,-lcp[j].fi); chkmax(ans[tr[i]],r[tr[i]]+1+query(1,1,n,l[tr[i]],r[tr[i]])); } For(i,1,q)wt(ans[i]); flush(); return 0; }