https://vjudge.net/contest/237352#problem/F
题意:给出一个字符串,判断该字符串能否分成三个回文串。
解法:运用manacher算法,求出以每个i为中心的回文串长度p[i],从而预处理出所有的前缀回文串和后缀回文串。
分别枚举每个前缀回文串和后缀回文串,判断中间的字符串是否也为回文串,判断方法为:找到中间字符串的中心点k,比较2*p[k]-1以及中间字符串长度的大小,若2*p[k]-1较大,则中间字符串也是回文串;否则不是。
manacher原理参考博客:https://segmentfault.com/a/1190000008484167 (求字符串的最长回文串长度)
manacher模板:
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 char s[1000]; 8 char s_new[2000]; 9 int p[2000]; 10 11 int Init() 12 { 13 int len = strlen(s); 14 s_new[0] = '$'; 15 s_new[1] = '#'; 16 int j = 2; 17 18 for (int i = 0; i < len; i++) 19 { 20 s_new[j++] = s[i]; 21 s_new[j++] = '#'; 22 } 23 24 s_new[j] = '\0'; // 别忘了哦 25 26 return j; // 返回 s_new 的长度 27 } 28 29 int Manacher() 30 { 31 int len = Init(); // 取得新字符串长度并完成向 s_new 的转换 32 int max_len = -1; // 最长回文长度 33 34 int id; 35 int mx = 0; 36 37 for (int i = 1; i < len; i++) 38 { 39 if (i < mx) 40 p[i] = min(p[2 * id - i], mx - i); // 需搞清楚上面那张图含义, mx 和 2*id-i 的含义 41 else 42 p[i] = 1; 43 44 while (s_new[i - p[i]] == s_new[i + p[i]]) // 不需边界判断,因为左有'$',右有'\0' 45 p[i]++; 46 47 // 我们每走一步 i,都要和 mx 比较,我们希望 mx 尽可能的远,这样才能更有机会执行 if (i < mx)这句代码,从而提高效率 48 if (mx < i + p[i]) 49 { 50 id = i; 51 mx = i + p[i]; 52 } 53 54 max_len = max(max_len, p[i] - 1); 55 } 56 57 return max_len; 58 } 59 60 int main() 61 { 62 while (printf("请输入字符串:\n")) 63 { 64 scanf("%s", s); 65 printf("最长回文长度为 %d\n\n", Manacher()); 66 } 67 return 0; 68 }
本题代码:
1 #include <bits/stdc++.h> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 #include <string> 7 #include <cmath> 8 #include <cstdlib> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <vector> 13 #include <set> 14 #include <bitset> 15 #include <iomanip> 16 #define ms(a, b) memset(a, b, sizeof(a)); 17 using namespace std; 18 typedef long long LL; 19 typedef pair<int, int> pii; 20 const int INF = 0x3f3f3f3f; 21 const int maxn = 4e4 + 10; 22 const int MAXN = 2e4 + 10; 23 const double eps = 1e-8; 24 const int mod = 1e9 + 7; 25 char s[maxn], ne[maxn]; 26 int pre[maxn], suf[maxn], p[maxn]; 27 28 void manacher() { 29 ne[0] = '$'; 30 ne[1] = '#'; 31 int j = 2; 32 int len1 = strlen(s); 33 for(int i = 0; i < len1; i++) { 34 ne[j++] = s[i]; 35 ne[j++] = '#'; 36 } 37 ne[j] = '\0'; 38 int len = j; 39 int mx = 0; 40 int id; 41 for(int i = 1; i < len; i++) { 42 if(i < mx) { 43 p[i] = min(p[2*id-i], mx-i); 44 } 45 else p[i] = 1; 46 while(ne[i-p[i]] == ne[i+p[i]]) p[i]++; 47 if(i + p[i] > mx) { 48 mx = i + p[i]; 49 id = i; 50 } 51 } 52 } 53 54 int main() 55 { 56 #ifdef local 57 freopen("case.in","r",stdin); 58 // freopen("out.in","w",stdout); 59 #endif 60 int T; 61 scanf("%d", &T); 62 while(T--) { 63 scanf("%s", s); 64 manacher(); 65 // for(int i = 1; i < len; i++) { 66 // printf("%c ", ne[i]); 67 // } 68 // cout << endl; 69 // for(int i = 1; i < len; i++) { 70 // printf("%d ", p[i]); 71 // } 72 // cout << endl; 73 int len = strlen(ne); 74 int l = 0, r = 0; 75 for(int i = 1; i < len; i++) { 76 if(p[i] == i && i != 1) pre[l++] = p[i]; 77 if(p[i] + i == len && i != len-1) suf[r++] = p[i]; 78 } 79 int i, j; 80 for(i = l-1; i >= 0; i--) { 81 for(j = 0; j < r; j++) { 82 int t1 = 2 * pre[i]; 83 int t2 = len - 1 - (2 * suf[j] - 1); 84 if(t1 > t2) continue; 85 int tmp = (t1 + t2) >> 1; 86 // if(p[tmp] == 1) continue; 87 if(2 * p[tmp] - 1 >= t2 - t1 + 1) break; 88 } 89 if(j < r) break; 90 } 91 if(i >= 0) printf("Yes\n"); 92 else printf("No\n"); 93 } 94 return 0; 95 }