Description
The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days: his mother is getting ill. Being worried about spending so much on railway tickets (Byterland is such a big country, and he has to spend 16 shours on train to his hometown), he decided only to send SMS with his mother.
The little cat lives in an unrich family, so he frequently comes to the mobile service center, to check how much money he has spent on SMS. Yesterday, the computer of service center was broken, and printed two very long messages. The brilliant little cat soon found out:
1. All characters in messages are lowercase Latin letters, without punctuations and spaces.
2. All SMS has been appended to each other – (i+1)-th SMS comes directly after the i-th one – that is why those two messages are quite long.
3. His own SMS has been appended together, but possibly a great many redundancy characters appear leftwards and rightwards due to the broken computer.
E.g: if his SMS is “motheriloveyou”, either long message printed by that machine, would possibly be one of “hahamotheriloveyou”, “motheriloveyoureally”, “motheriloveyouornot”, “bbbmotheriloveyouaaa”, etc.
4. For these broken issues, the little cat has printed his original text twice (so there appears two very long messages). Even though the original text remains the same in two printed messages, the redundancy characters on both sides would be possibly different.
You are given those two very long messages, and you have to output the length of the longest possible original text written by the little cat.
Background:
The SMS in Byterland mobile service are charging in dollars-per-byte. That is why the little cat is worrying about how long could the longest original text be.
Why ask you to write a program? There are four resions:
1. The little cat is so busy these days with physics lessons;
2. The little cat wants to keep what he said to his mother seceret;
3. POJ is such a great Online Judge;
4. The little cat wants to earn some money from POJ, and try to persuade his mother to see the doctor :(Input
Two strings with lowercase letters on two of the input lines individually. Number of characters in each one will never exceed 100000.
Output
A single line with a single integer number – what is the maximum length of the original text written by the little cat.
Sample Input
yeshowmuchiloveyoumydearmotherreallyicannotbelieveit yeaphowmuchiloveyoumydearmotherSample Output
27给你两个长字符串,要你输出这两个字符串的最长公共连续子串长度.
首先如果这两个长字符串存在某个最长的公共子串,那么该子串一定分别是这两个串的后缀的前缀.所以我们将两个串中间加一个符号’$’然后连接起来形成一个新串(还要添尾0).然后我们求这个新串的height数组值,我们从sa[1]到新串长sa[n-1]依次扫描字典序相邻的两个后缀的LCP,如果这两个后缀分别属于之前不同的两个串,那么他们的LCP值就可能是他们最长连续公共子串的长度。否则的话就不是。
为什么上面的做法对呢?想想假设串a和串b存在最长字串c(长len),那么c是a串的后缀i的前缀,c是b串的后缀j的前缀。所以在新串中按字典序排序的height数组,后缀i和后缀j一定是相邻的。假设后缀i与后缀j之间还有后缀k,无论后缀k属于a串还是b串,k肯定与i与j的公共部分要>=len(想想是不是这样?)
另外如果我们连接两个原始串,中间不加’$’符号的话,会出现什么情况呢?比如串aaa和串aaaaaaa,那么就会算的他们的后缀LCP可能为6了,这明显是错的.所以要分隔符’$’.
AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include<queue>
#include<map>
#include<iomanip>
#include<math.h>
using namespace std;
typedef long long ll;
typedef double ld;
const int maxn=200000+1000;
int len1,len2;//分别为串1和串2的长度
struct SuffixArray
{
char s[maxn];
int sa[maxn],rank[maxn],height[maxn];
int t1[maxn],t2[maxn],c[maxn],n;
void build_sa(int m)
{
int i,*x=t1,*y=t2;
for(i=0; i<m; i++)
c[i]=0;
for(i=0; i<n; i++)
c[x[i]=s[i]]++;
for(i=1; i<m; i++)
c[i]+=c[i-1];
for(i=n-1; i>=0; i--)
sa[--c[x[i]]]=i;
for(int k=1; k<=n; k<<=1)
{
int p=0;
for(i=n-k; i<n; i++)
y[p++]=i;
for(i=0; i<n; i++)
if(sa[i]>=k)
y[p++]=sa[i]-k;
for(i=0; i<m; i++)
c[i]=0;
for(i=0; i<n; i++)
c[x[y[i]]]++;
for(i=1; i<m; i++)
c[i]+=c[i-1];
for(i=n-1; i>=0; i--)
sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;
x[sa[0]]=0;
for(i=1; i<n; i++)
x[sa[i]]= y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
if(p>=n)
break;
m=p;
}
}
void build_height()
{
int i,j,k=0;
for(i=0; i<n; i++)
rank[sa[i]]=i;
for(i=0; i<n; i++)
{
if(k)
k--;
j=sa[rank[i]-1];
while(s[i+k]==s[j+k])
k++;
height[rank[i]]=k;
}
}
int solve()
{
int ans=0;
for(int i=2; i<n; i++)
{
int a1=sa[i-1],a2=sa[i];
if(a1>a2)
swap(a1,a2);
if(a1>=0&&a1<=len1-1&&a2>=len1+1&&a2<=len1+len2)
ans = max(ans,height[i]);
}
return ans;
}
} sa;
int main()
{
scanf("%s",sa.s);
len1=strlen(sa.s);
sa.s[len1]=1;
scanf("%s",sa.s+len1+1);
len2=strlen(sa.s)-len1-1;
sa.n=len1+len2+2;
sa.s[len1+len2+1]=0;
sa.build_sa(128);
sa.build_height();
printf("%d\n",sa.solve());
return 0;
}