若在假设重复子串的长度最多为L的限制下有解, 则对于任意一个比L小的限制L'<L, 也一定有解. 这就说明存在解的连续性, 这样就可以用二分查找答案长度L.
给出一个关于LCP的定理LCP(SA[i], SA[j]) = RMQ(Height[i+1..j]). 由此, 若存在k, 满足Height[k] < L, 则对于所有i, j 满足i < k < j, 有LCP(SA[i], SA[j]) < L. 即公共长度至少为L的两个后缀, 不会跨过一个小于L的Height低谷k, 所以我们可以得到一些由这些低谷划分开的连续的段.
在某段内, 若存在i, j 满足SA[i]+L<SA[j], 则存在一个长度至少为L的2个相同不交迭子串. 实现时只要记录在每段内, 最大和最小的SA值即可.
--Amber大牛,《男人不容易系列Solution》
最终还是用了大牛的思路,再次自觉思维的狭隘!!
#include
<
iostream
>
using
namespace
std;
#define
MAXN 20010
int
a[MAXN],b[MAXN],array[
4
][MAXN],
*
sa,
*
nsa,
*
rank,
*
nrank,height[MAXN],n;
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[a[i]]
++
;
for
(i
=
1
;i
<=
256
;i
++
)
b[i]
+=
b[i
-
1
];
for
(i
=
n
-
1
;i
>=
0
;i
--
)
sa[
--
b[a[i]]]
=
i;
for
(rank[sa[
0
]]
=
0
,i
=
1
;i
<
n;i
++
){
rank[sa[i]]
=
rank[sa[i
-
1
]];
if
(a[sa[i]]
!=
a[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
(k
=
0
,i
=
0
;i
<
n;i
++
){
if
(rank[i]
==
0
)
height[rank[i]]
=
0
;
else
{
for
(j
=
sa[rank[i]
-
1
];a[i
+
k]
==
a[j
+
k];k
++
);
height[rank[i]]
=
k;
if
(k
>
0
)
k
--
;
}
}
}
bool
OK(
int
len){
int
i,mn,mx;
mn
=
n;
mx
=
0
;
for
(i
=
1
;i
<
n;i
++
){
if
(height[i]
<
len){
mn
=
n;
mx
=
0
;
}
else
{
if
(sa[i]
>
mx)
mx
=
sa[i];
if
(sa[i]
<
mn)
mn
=
sa[i];
if
(sa[i
-
1
]
>
mx)
mx
=
sa[i
-
1
];
if
(sa[i
-
1
]
<
mn)
mn
=
sa[i
-
1
];
if
(mx
-
mn
>=
len)
return
true
;
}
}
return
false
;
}
int
main(){
int
i,ans,l,r,len;
while
(scanf(
"
%d
"
,
&
n)
&&
n){
for
(i
=
0
;i
<
n;i
++
)
scanf(
"
%d
"
,
&
a[i]);
for
(i
=
1
;i
<
n;i
++
)
a[i
-
1
]
=
a[i]
-
a[i
-
1
]
+
88
;
n
--
;
a[n
++
]
=
0
;
make_sa();
cal_height();
if
(
!
OK(
4
)){
printf(
"
0\n
"
);
continue
;
}
ans
=
0
;
l
=
0
;r
=
n
-
1
;
while
(l
<=
r){
len
=
(l
+
r)
/
2
;
if
(OK(len)){
ans
=
len;
l
=
len
+
1
;
}
else
r
=
len
-
1
;
}
printf(
"
%d\n
"
,ans
+
1
);
}
return
0
;
}