bzoj4755: [Jsoi2016]扭动的回文串
Description
JYY有两个长度均为N的字符串A和B。
一个“扭动字符串S(i,j,k)由A中的第i个字符到第j个字符组成的子串
与B中的第j个字符到第k个字符组成的子串拼接而成。
比如,若A=’XYZ’,B=’UVW’,则扭动字符串S(1,2,3)=’XYVW’。
JYY定义一个“扭动的回文串”为如下情况中的一个:
1.A中的一个回文串;
2.B中的一个回文串;
3.或者某一个回文的扭动字符串S(i,j,k)
现在JYY希望找出最长的扭动回文串。
Input
第一行包含一个正整数N。
第二行包含一个长度为N的由大写字母组成的字符串A。
第三行包含一个长度为N的由大写字母组成的字符串B。
1≤N≤10^5。
Output
输出的第一行一个整数,表示最长的扭动回文串。
Sample Input
5
ABCDE
BAECB
Sample Output
5
最佳方案中的扭动回文串如下所示(不在回文串中的字符用.表示):
.BC..
..ECB
分析
设扭动的回文串为
M(i,j)
M
(
i
,
j
)
,则
M(i,j)=Sa(i,k)+Paorb(k,l)+Sb(l,j)
M
(
i
,
j
)
=
S
a
(
i
,
k
)
+
P
a
o
r
b
(
k
,
l
)
+
S
b
(
l
,
j
)
其中
Paorb(k,l)
P
a
o
r
b
(
k
,
l
)
是关于某个中心点的最长的回文串,
(k,l)
(
k
,
l
)
区间的开闭由其是在A串还是B串中决定。
Sa(i,k),Sb(l,j)
S
a
(
i
,
k
)
,
S
b
(
l
,
j
)
是反对称的。
然后对于A和B中的每个对称中心,我们manacher一遍求出
Paorb(k,l)
P
a
o
r
b
(
k
,
l
)
,两边二分+Hash即可。
代码
/**************************************************************
Problem: 4755
User: 2014lvzelong
Language: C++
Result: Accepted
Time:704 ms
Memory:4808 kb
****************************************************************/
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1e5 + 10;
unsigned long long se = 31;
char s[N << 1], a[N], b[N];
int n, f[N << 1], ans;
unsigned long long ha[N], hb[N], bin[N];
void Solve(char *S) {
s[0] = '.'; int id = 0, tot = 0;
for(int i = 1;i <= n; ++i) {
s[++tot] = S[i];
if(i != n) s[++tot] = '#';
}
for(int i = 1;i <= tot; ++i) {
if(i < id + f[id]) f[i] = min(id + f[id] - i, f[(id << 1) - i]);
else f[i] = 0;
while(s[i - f[i] - 1] == s[i + f[i] + 1]) ++f[i];
if(i + f[i] > id + f[id]) id = i;
int L = i - f[i] + 2 >> 1, R = i + f[i] + 1 >> 1;
if(S == a) --R; else ++L; int res = 0;
for(int l = 0, r = min(L - 1, n - R); l <= r; ) {
int mid = l + r >> 1;
if(ha[L - 1] - ha[L - mid - 1] * bin[mid] == hb[R + 1] - hb[R + mid + 1] * bin[mid])
res = mid, l = mid + 1;
else r = mid - 1;
}
ans = max(ans, R - L + 2 + (res << 1));
}
}
int main() {
scanf("%d%s%s", &n, a + 1, b + 1);
bin[0] = 1; for(int i = 1;i <= n; ++i) bin[i] = bin[i - 1] * se;
for(int i = 1;i <= n; ++i) ha[i] = ha[i - 1] * se + a[i];
for(int i = n; i; --i) hb[i] = hb[i + 1] * se + b[i];
Solve(a); Solve(b);
printf("%d\n", ans);
return 0;
}