●BZOJ 3796 Mushroom追妹纸
题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=3796
题解:
题意:
给出三个串 A,B,C
找出一个最长串 S,
使得 S是A,B 的子串,但是 C不是S的子串。
首先,对于第一二个限制,只需要把 A,B串用一个分隔符连接在一起。
求出sa[],rank[],height[]数组,
那么在排好序的后缀中,相邻的两个后缀如果一个属于A串(令在A串p位置),另一个属于B串的话,
则可能贡献答案。 但应该贡献多少呢?
由于有 C 的限制,即在LCP中选出的最长前缀里不能出现 C串。
所以考虑如下做法。
定义 appear[i] 表示 A串的 i位置后面第一次出现 C串的开始位置。
求出这个以后,那么就可以贡献答案了:
ANS=max(ANS,min(hei[i],appear[i]-p+LenC-1))
以下是求pre数组的做法:
把 A串作为文本串,C串作为匹配串,用 KMP去匹配。
并在 A串中每一个出现 C串的开始位置打上标记
然后反向跑一边,得出appear[]数组。
总的复杂度 (Nlog2N+N)
代码:
#include<cstdio> #include<cstring> #include<iostream> #define MAXN 100500 #define INF 0x3f3f3f3f #define filein(x) freopen(#x".in","r",stdin); #define fileout(x) freopen(#x".out","w",stdout); using namespace std; char S[MAXN],A[MAXN],B[MAXN],C[MAXN]; int sa[MAXN],rak[MAXN],hei[MAXN],app[MAXN]; int L1,L2,L3,ANS; void build(int N,int M){ static int cc[MAXN],ta[MAXN],tb[MAXN],*x,*y,h,p; x=ta; y=tb; h=0; for(int i=0;i<M;i++) cc[i]=0; for(int i=0;i<N;i++) cc[x[i]=S[i]]++; for(int i=1;i<M;i++) cc[i]+=cc[i-1]; for(int i=N-1;i>=0;i--) sa[--cc[x[i]]]=i; for(int k=1;p=0,k<N;k<<=1){ for(int i=N-k;i<N;i++) y[p++]=i; for(int i=0;i<N;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<M;i++) cc[i]=0; for(int i=0;i<N;i++) cc[x[y[i]]]++; for(int i=1;i<M;i++) cc[i]+=cc[i-1]; for(int i=N-1;i>=0;i--) sa[--cc[x[y[i]]]]=y[i]; swap(x,y); y[N]=-1; x[sa[0]]=0; M=1; for(int i=1;i<N;i++) x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?M-1:M++; if(M>=N) break; } for(int i=0;i<N;i++) rak[sa[i]]=i; for(int i=0,j;i<N;i++){ if(h) h--; if(rak[i]){ j=sa[rak[i]-1]; while(S[i+h]==S[j+h]) h++; } hei[rak[i]]=h; } } void KMP(char *T,char *S){ static int nxt[MAXN],i,j,k,lT,lS; memset(app,0x3f,sizeof(app)); nxt[0]=-1; lT=strlen(T); lS=strlen(S); j=0; k=-1; while(j<lS){ if(k==-1||S[j]==S[k]) j++,k++,nxt[j]=k; else k=nxt[k]; } i=0; j=0; while(i<lT){ if(j==-1||T[i]==S[j]){ i++; j++; if(!S[j]) app[i-lS]=i-lS; } else j=nxt[j]; } for(int i=lT-1;i>=0;i--) app[i]=min(app[i],app[i+1]); } bool bel(int p){ if(p<L1) return 0; else return 1; } int main() { int N; scanf(" %s %s %s",A,B,C); L1=strlen(A); L2=strlen(B); L3=strlen(C); N=L1+L2+1; for(int i=0;i<L1;i++) S[i]=A[i]; S[L1]='&'; for(int i=0;i<L2;i++) S[L1+i+1]=B[i]; S[N]=0; build(N,300); KMP(A,C); for(int i=1,p,q;i<N;i++){ if(hei[i]<=ANS||!(bel(sa[i-1])^bel(sa[i]))) continue; if(!bel(sa[i-1])) p=sa[i-1]; else p=sa[i]; q=app[p]; ANS=max(ANS,min(hei[i],q-p+L3-1)); } printf("%d",ANS); return 0; }
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas