You are the King of Byteland. Your agents have just intercepted a
batch of encrypted enemy messages concerning the date of the planned
attack on your island. You immedietaly send for the Bytelandian
Cryptographer, but he is currently busy eating popcorn and claims that
he may only decrypt the most important part of the text (since the
rest would be a waste of his time). You decide to select the fragment
of the text which the enemy has strongly emphasised, evidently
regarding it as the most important. So, you are looking for a fragment
of text which appears in all the messages disjointly at least twice.
Since you are not overfond of the cryptographer, try to make this
fragment as long as possible.Input
The first line of input contains a single positive integer t<=10, the
number of test cases. t test cases follow. Each test case begins with
integer n (n<=10), the number of messages. The next n lines contain
the messages, consisting only of between 2 and 10000 characters
‘a’-‘z’, possibly with some additional trailing white space which
should be ignored.Output
For each test case output the length of longest string which appears
disjointly at least twice in all of the messages.
把所有字符串连起来求height,二分答案之后分组,只要验证每一组里是否能让每一串都符合条件。需要符合的条件是出现位置的最大值和最小值之差不小于k。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[200010];
int sa[200010],rank[200010],height[200010],cnt[200010],t1[200010],t2[200010],
n,l,mn[12],mx[12],bel[200010];
bool flag[12];
void init()
{
int i,tem,j;
l=0;
scanf("%d",&n);
for (i=1;i<=n;i++)
{
scanf("%s",s+l+1);
tem=strlen(s+1);
for (j=l+1;j<=tem;j++)
bel[j]=i;
l=tem+1;
s[l]=i;
s[l+1]=0;
}
}
void make()
{
int i,j,k,m='z',p,*x=t1,*y=t2;
for (i=1;i<=m;i++)
cnt[i]=0;
for (i=1;i<=l;i++)
cnt[x[i]=s[i]]++;
for (i=2;i<=m;i++)
cnt[i]+=cnt[i-1];
for (i=l;i;i--)
sa[cnt[x[i]]--]=i;
for (k=1;k<=l;k<<=1)
{
p=0;
for (i=l-k+1;i<=l;i++)
y[++p]=i;
for (i=1;i<=l;i++)
if (sa[i]-k>=1)
y[++p]=sa[i]-k;
for (i=1;i<=m;i++)
cnt[i]=0;
for (i=1;i<=l;i++)
cnt[x[y[i]]]++;
for (i=2;i<=m;i++)
cnt[i]+=cnt[i-1];
for (i=l;i;i--)
sa[cnt[x[y[i]]]--]=y[i];
swap(x,y);
p=x[sa[1]]=1;
for (i=2;i<=l;i++)
{
if (y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) p++;
x[sa[i]]=p;
}
if ((m=p)>l) break;
}
for (i=1;i<=l;i++)
rank[sa[i]]=i;
for (i=1,k=0;i<=l;i++)
{
if (k) k--;
if (rank[i]==0) continue;
while (s[i+k]==s[sa[rank[i]-1]+k]) k++;
height[rank[i]]=k;
}
}
bool ok(int k)
{
int i,now;
if (!k) return 1;
for (i=1;i<=l;i++)
if (height[i]<k)
{
memset(mn,0x3f,sizeof(mn));
memset(mx,-1,sizeof(mx));
memset(flag,0,sizeof(flag));
mn[bel[sa[i]]]=mx[bel[sa[i]]]=sa[i];
now=0;
}
else
{
mn[bel[sa[i]]]=min(mn[bel[sa[i]]],sa[i]);
mx[bel[sa[i]]]=max(mx[bel[sa[i]]],sa[i]);
if (!flag[bel[sa[i]]]&&mx[bel[sa[i]]]-mn[bel[sa[i]]]>=k)
{
flag[bel[sa[i]]]=1;
now++;
if (now==n) return 1;
}
}
return 0;
}
int main()
{
int T,ll,rr,mid;
scanf("%d",&T);
while (T--)
{
init();
make();
ll=0;
rr=l;
while (ll<rr)
{
mid=(ll+rr+1)/2;
if (ok(mid)) ll=mid;
else rr=mid-1;
}
printf("%d\n",ll);
}
}