http://www.elijahqi.win/archives/630
Description
Mushroom最近看上了一個漂亮妹紙。他選擇一種非常經典的手段來表達自己的心意——寫情書。考慮到自己的表達能力,Mushroom決定不手寫情書。他從網上找到了兩篇極佳的情書,打算選擇其中共同的部分。另外,Mushroom還有個一個情敵Ertanis,此人也寫了封情書給妹子。
Mushroom不希望自己的情書中完整的出現了情敵的情書。(這樣抄襲的事情就暴露了)。
Mushroom把兩封情書分別用字符串s1和s2來表示,Ertanis的情書用字符串s3來表示,他要截取的部分用字符串w表示。
需滿足:
1、w是s1的子串
2、w是s2的子串
3、s3不是w的子串
4、w的長度應儘可能大
所謂子串是指:在字符串中連續的一段
【輸入】
輸入文件爲girl.in
輸入有三行,第一行爲一個字符串s1第二行爲一個字符串s2,
第三行爲一個字符串s3。輸入僅含小寫字母,字符中間不含空格。
【輸出】
輸出文件爲girl.out
輸出僅有一行,爲w的最大可能長度,如w不存在,則輸出0。
【輸入樣例】
abcdef
abcf
bc
【輸出樣例】
2
【樣例解釋】
s1和s2的公共子串有abc,ab,bc,a,b,c,f,其中abc,bc包含子串bc不合法,所以最長的合法子串爲ab。
【數據規模】
對於30%的數據:1<=s1、s2、s3的長度<=500
對於60%的數據:1<=s1、s2、s3的長度<=5000
對於100%的數據:1<=s1、s2的長度<=50000,1<=s3的長度<=10000
Input
輸入有三行,第一行爲一個字符串s1第二行爲一個字符串s2,
第三行爲一個字符串s3。輸入僅含小寫字母,字符中間不含空格。
Output
輸出僅有一行,爲w的最大可能長度,如w不存在,則輸出0。
Sample Input
abcdef
abcf
bc
Sample Output
2
【樣例解釋】
s1和s2的公共子串有abc,ab,bc,a,b,c,f,其中abc,bc包含子串bc不合法,所以最長的合法子串爲ab。
HINT
對於100%的數據:1<=s1、s2的長度<=50000,1<=s3的長度<=10000
題意要求我們找一個串1&串2完整包含的子串,並且串3不完整在他們裏面
首先我們需要製作一個L數組表示L[i] 表示 從L[i]->i這個區間完整包含了s3並且這個區間的長度最小
如何製作L數組我們可以用kmp去匹配
然後二分驗證答案是否正確 中間有分隔符,不要忘記處理
#include<cstdio>
#include<cstring>
#define N 110000
int n;char s[N>>1],t[N>>1];int a[N],len[5],rank[N<<1],rank1[N],height[N],tmp[N],sa[N],count[N],L[N],bl[N],next[N>>1];
inline int max(int a,int b){
return a>b?a:b;
}
inline bool judge(int x){
bool f[3];f[1]=f[2]=false;
for (int i=1;i<=n;++i){
if (height[i]>=x){
if(sa[i]<=L[sa[i]+x-1]) continue;
f[bl[sa[i]]]=true;
}else{
if (f[1]&&f[2]) return true;
f[1]=f[2]=false;
if (sa[i]<=L[sa[i]+x-1])continue;
f[bl[sa[i]]]=true;
}
}
return false;
}
int main(){
//freopen("bzoj3796.in","r",stdin);
n=1;int l=1,r=0;int m=30;
for (int i=1;i<=2;++i){
scanf("%s",s+1);len[i]=strlen(s+1);
r=max(r,len[i]);for (int j=0;j<len[i];++j) a[j+n]=s[j+1]-'a'+1,bl[j+n]=i;
n+=len[i];a[n++]=m++;
}n-=1;
scanf("%s",t+1);len[3]=strlen(t+1);
//sa
for (int i=1;i<=n;++i) count[a[i]]=1;
for (int i=1;i<=m;++i) count[i]+=count[i-1];
for (int i=1;i<=n;++i) rank[i]=count[a[i]];
int k=0;
for (int p=1;k!=n;p<<=1,m=k){
for (int i=1;i<=m;++i) count[i]=0;
for (int i=1;i<=n;++i) count[rank[i+p]]++;
for (int i=1;i<=m;++i) count[i]+=count[i-1];
for (int i=n;i>=1;--i) tmp[count[rank[i+p]]--]=i;
for (int i=1;i<=m;++i) count[i]=0;
for (int i=1;i<=n;++i) count[rank[i]]++;
for (int i=1;i<=m;++i) count[i]+=count[i-1];
for (int i=n;i>=1;--i) sa[count[rank[tmp[i]]]--]=tmp[i];
memcpy(rank1,rank,sizeof(rank)>>1);
rank[sa[1]]=k=1;
for (int i=2;i<=n;++i){
if (rank1[sa[i]+p]!=rank1[sa[i-1]+p]||rank1[sa[i]]!=rank1[sa[i-1]])++k;
rank[sa[i]]=k;
}
}
k=0;
for (int i=1;i<=n;++i){
if (rank[i]==1) continue;
k=k==0?0:k-1;
while (a[i+k]==a[sa[rank[i]-1]+k])++k;
height[rank[i]]=k;
}
//getnext
next[1]=0;
for (int i=2;i<=len[3];++i){
while (k&&t[k+1]!=t[i]) k=next[k];
if (t[k+1]==t[i])++k;
next[i]=k;
}
// make Array L[]
int last=0;k=0;
for (int i=1;i<=len[2];++i){
while (k&&s[i]!=t[k+1]) k=next[k];
if (s[i]==t[k+1]) ++k;
if (k==len[3]) last=len[1]+1+i-len[3]+1;//別忘記處理分隔符x
L[len[1]+i+1]=last;
}
while (l<=r){
int mid=(l+r)>>1;
if (judge(mid)) l=mid+1;else r=mid-1;
}
printf("%d",l-1);
return 0;
}