您的位置:首页 > Web前端 > JavaScript

bzoj4755: [Jsoi2016]扭动的回文串 manacher+二分+Hash

2018-03-10 21:03 381 查看

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)=Sa(i,k)+Paorb(k,l)+Sb(l,j)

其中Paorb(k,l)Paorb(k,l)是关于某个中心点的最长的回文串,(k,l)(k,l)区间的开闭由其是在A串还是B串中决定。Sa(i,k),Sb(l,j)Sa(i,k),Sb(l,j)是反对称的。

然后对于A和B中的每个对称中心,我们manacher一遍求出Paorb(k,l)Paorb(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
, b
;
int n, f[N << 1], ans;
unsigned long long ha
, hb
, bin
;
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;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: