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
5ABCDE
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; }
相关文章推荐
- [BZOJ]4755: [Jsoi2016]扭动的回文串
- [bzoj4755][JSOI2016]扭动的回文串
- BZOJ4755 [JSOI2016]扭动的回文串 【后缀数组】【manacher】
- BZOJ4755 [Jsoi2016]扭动的回文串
- [bzoj4755][Jsoi2016]扭动的回文串
- BZOJ4755: [JSOI2016]扭动的回文串——题解
- BZOJ 1014: [JSOI2008]火星人prefix [splay 二分+hash] 【未完】
- BZOJ.1014.[JSOI2008]火星人(Splay 二分 Hash)
- [二分+DFS序上DP]BZOJ 4753—— [Jsoi2016]最佳团体
- BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分
- BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分
- bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)
- [BZOJ]1567: [JSOI2008]Blue Mary的战役地图 二分+hash
- BZOJ4755 [Jsoi2016]扭动的回文串
- BZOJ 1567: [JSOI2008]Blue Mary的战役地图( 二分答案 + hash )
- BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
- bzoj 1567: [JSOI2008]Blue Mary的战役地图【二分+hash】
- [BZOJ]1014: [JSOI2008]火星人prefix splay+hash+二分
- bzoj 1567: [JSOI2008]Blue Mary的战役地图 (二分+hash)
- BZOJ 1014 JSOI 2008 火星人prefix Splay维护字符串Hash + 二分