BZOJ2342 Manacher + set
题一:别人介绍的一道题,题意是给出一个序列,我们要求出一段最常的连续子序列,满足:该子序列能够被平分为三段,第一段和第二段形成回文串,第二段和第三段形成回文串。
题二:BZOJ2342和这题非常的相似,BZOJ的题意是说求出一个最长的回文串,该串能平均分四段,满足整体是回文串,前一半是回文串,后一半也是回文串。
对于第一个问题的做法是:Manacher后,枚举每一个位置i(一定是#),作为第二个中心,那么我们就需要在[i-Mp[i], i]之间找到一个最小的j,满足以j为中心的回文串能够覆盖到位置i, 最先找到的,贡献的答案肯定最大。是不是对于每个位置i,我们都需要在前面找所有的范围内的j呢? jiaru摸个j形成的回文不能覆盖到i, 那么这个j肯定不能覆盖到k(k>i), 即这个j对之后的位置都没有贡献,可以删除, 而每个位置最多被删一次, 复杂度为nlog
题二:
/************************************************************** Problem: 2342 User: foratrp Language: C++ Result: Accepted Time:748 ms Memory:18280 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <string> #include <stack> #include <cmath> #include <cstdlib> #include <iostream> #include <map> #include <set> using namespace std; const int INF = 0x3f3f3f3f; typedef long long ll; const int N = 5e5 + 100; char Ma[N <<1]; int Mp[N << 1]; char s[N]; void Manacher(int len) { int l = 0; Ma[l++] = '$'; Ma[l++] = '#'; for(int i = 0; i < len; ++i) { Ma[l++] = s[i]; Ma[l++] = '#'; } Ma[l] = 0; int mx = 0, id = 0; for(int i = 0; i < l; ++i) { Mp[i] = mx > i ? min(Mp[2 * id - i], mx - i) : 1; while (Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i]++; if(i + Mp[i] > mx) mx = i + Mp[i], id = i; } // for(int i = 0; i < l; ++i) printf("%d ", Mp[i]); } set<int> ms; void solve(int n) { int ans = 0; ms.clear(); for(int i = 3; i < 2 * n + 2; i += 2) ms.insert(i); for(int i = 5; i < 2 * n + 2; i += 2) { int j = i - (Mp[i] / 2); if(j % 2 == 0) j++; while(j != i) { if(j + Mp[j] > i) { ans = max(ans, (i - j) * 2); break; } else { ms.erase(j); j = *ms.lower_bound(j); } } } printf("%d\n", ans); } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); #endif int len; while(~scanf("%d", &len)) { scanf("%s", s); Manacher(len); solve(len); } return 0; }
题一:
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <string> #include <stack> #include <cmath> #include <cstdlib> #include <iostream> #include <map> #include <set> using namespace std; const int INF = 0x3f3f3f3f; typedef long long ll; const int N = 5e5 + 100; int Ma[N <<1]; int Mp[N << 1]; int s[N]; void Manacher(int len) { int l = 0; Ma[l++] = -INF; Ma[l++] = INF; for(int i = 0; i < len; ++i) { Ma[l++] = s[i]; Ma[l++] = INF; } Ma[l] = 0; int mx = 0, id = 0; for(int i = 0; i < l; ++i) { Mp[i] = mx > i ? min(Mp[2 * id - i], mx - i) : 1; while (Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i]++; if(i + Mp[i] > mx) mx = i + Mp[i], id = i; } //wwww for(int i = 0; i < l; ++i) printf("%d ", Mp[i]); } set<int> ms; void solve(int n) { int ans = 0; ms.clear(); for(int i = 3; i < 2 * n + 2; i += 2) ms.insert(i); for(int i = 5; i < 2 * n + 2; i += 2) { int j = i - Mp[i] + 1; while(j != i) { if(j + Mp[j] > i) { ans = max(ans, (i - j) / 2 * 3); break; } else { ms.erase(j); j = *ms.lower_bound(j); } } } printf("%d\n", ans); } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); #endif int cas, _ = 1, len; scanf("%d", &cas); while(cas --) { scanf("%d", &len); for(int i = 0; i < len; ++i) scanf("%d", &s[i]); Manacher(len); printf("Case #%d: ", _++); solve(len); } return 0; }