思路:以第一个串为基串,将另外N-1个串分别与基串拼接跑后缀数组,记录基串每一个位置与另外一个串的最长匹配长度,求出每一个位置在和别的所有串跑后缀数组时所得的最长匹配中的最小值,最后求出所有位置中的最大值就是所求。
也可以用类似Music Theme的二分枚举搞掉,但是代码太丑陋所以就不贴啦
/*
Memory: 428K Time: 188MS
Language: C++ Result: Accepted
*/
#include
<
iostream
>
using
namespace
std;
#define
MAXN 500
int
b[MAXN],array[
4
][MAXN],
*
sa,
*
nsa,
*
rank,
*
nrank,height[MAXN],len,n,m,mnlen[MAXN],mxlen[MAXN];
char
str[
4001
][
205
],ss[MAXN];
void
make_sa(){
int
i,k;
sa
=
array[
0
];
nsa
=
array[
1
];
rank
=
array[
2
];
nrank
=
array[
3
];
memset(b,
0
,
sizeof
(b));
for
(i
=
0
;i
<
n;i
++
)
b[ss[i]]
++
;
for
(i
=
1
;i
<=
256
;i
++
)
b[i]
+=
b[i
-
1
];
for
(i
=
n
-
1
;i
>=
0
;i
--
)
sa[
--
b[ss[i]]]
=
i;
for
(rank[sa[
0
]]
=
0
,i
=
1
;i
<
n;i
++
){
rank[sa[i]]
=
rank[sa[i
-
1
]];
if
(ss[sa[i]]
!=
ss[sa[i
-
1
]])
rank[sa[i]]
++
;
}
for
(k
=
1
;k
<
n
&&
rank[sa[n
-
1
]]
<
n
-
1
;k
*=
2
){
for
(i
=
0
;i
<
n;i
++
)
b[rank[sa[i]]]
=
i;
for
(i
=
n
-
1
;i
>=
0
;i
--
)
if
(sa[i]
-
k
>=
0
)
nsa[b[rank[sa[i]
-
k]]
--
]
=
sa[i]
-
k;
for
(i
=
n
-
k;i
<
n;i
++
)
nsa[b[rank[i]]
--
]
=
i;
for
(nrank[nsa[
0
]]
=
0
,i
=
1
;i
<
n;i
++
){
nrank[nsa[i]]
=
nrank[nsa[i
-
1
]];
if
(rank[nsa[i]]
!=
rank[nsa[i
-
1
]]
||
rank[nsa[i]
+
k]
!=
rank[nsa[i
-
1
]
+
k])
nrank[nsa[i]]
++
;
}
int
*
t
=
sa;sa
=
nsa;nsa
=
t;
t
=
rank;rank
=
nrank;nrank
=
t;
}
}
void
cal_height(){
int
i,j,k;
for
(i
=
0
,k
=
0
;i
<
n;i
++
){
if
(rank[i]
==
0
)
height[rank[i]]
=
0
;
else
{
for
(j
=
sa[rank[i]
-
1
];ss[i
+
k]
==
ss[j
+
k];k
++
);
height[rank[i]]
=
k;
if
(k
>
0
)
k
--
;
}
}
}
void
make_mxlen(){
memset(mxlen,
0
,
sizeof
(mxlen));
int
i,mn
=
INT_MAX;
mxlen[
0
]
=
0
;
for
(i
=
1
;i
<
n;i
++
){
if
(height[i]
<
mn)
mn
=
height[i];
if
(sa[i]
<
len){
if
(mn
==
INT_MAX)
mxlen[sa[i]]
=
0
;
else
mxlen[sa[i]]
=
mn;
}
else
{
mn
=
INT_MAX;
}
}
bool
first
=
true
;
mn
=
INT_MAX;
for
(i
=
n
-
1
;i
>=
1
;i
--
){
if
(sa[i]
<
len){
if
(mn
!=
INT_MAX)
if
(mn
>
mxlen[sa[i]])
mxlen[sa[i]]
=
mn;
}
else
{
mn
=
height[i];
first
=
false
;
}
if
(
!
first
&&
height[i]
<
mn)
mn
=
height[i];
}
}
int
main(){
int
i,j,t,mx,mxtag;
while
(scanf(
"
%d
"
,
&
m)
&&
m){
memset(mnlen,
0x7f
,
sizeof
(mnlen));
for
(i
=
0
;i
<
m;i
++
)
scanf(
"
%s
"
,str[i]);
len
=
strlen(str[
0
]);
str[
0
][len
++
]
=
'
#
'
;
str[
0
][len]
=
'
\0
'
;
for
(i
=
1
;i
<
m;i
++
){
strcpy(ss,str[
0
]);
strcat(ss,str[i]);
n
=
len
+
strlen(str[i]);
ss[n
++
]
=
'
$
'
;
ss[n]
=
'
\0
'
;
make_sa();
cal_height();
//
记录基串每一个位置与另外一个串的最长匹配长度
make_mxlen();
//
求出每一个位置在和别的所有串跑后缀数组时所得的最长匹配中的最小值
for
(j
=
0
;j
<
len;j
++
)
if
(mxlen[j]
<
mnlen[j])
mnlen[j]
=
mxlen[j];
}
strcpy(ss,str[
0
]);
n
=
len;
//
若有多个匹配符合答案则输出字典序最小的
//
估需要对基串重建后缀数组
make_sa();
mx
=
0
;
for
(i
=
1
;i
<
n;i
++
){
if
(mnlen[sa[i]]
>
mx){
mx
=
mnlen[sa[i]];
mxtag
=
sa[i];
}
}
if
(mx){
for
(i
=
0
;i
<
mx;i
++
)
printf(
"
%c
"
,ss[mxtag
+
i]);
printf(
"
\n
"
);
}
else
printf(
"
IDENTITY LOST\n
"
);
}
return
0
;
}