hdu 5340 Manachers + 枚举

来源:互联网 发布:淘宝冻结账户怎么解冻 编辑:程序博客网 时间:2024/05/24 06:45

题意:给你一个字符串问能否拆分为三个回文字符串?能就输出yes,否则输出no。


知识补充:

最长回文子串算法(Manacher算法):

求解最长回文子串的线性时间复杂度算法,主要是通过中心扩展的方法极大地避免了重复计算。实现如下:

  • 为了避免对字符串奇偶数的讨论,先对字符串做预处理如下:
规则为在字符间和两边插入'#'字符,为了避免越界处理,最两边插入'^''$'字符。原本字符串为:asd预处理后为:^#a#s#d#$
  • 然后实现部分:设置两个变量:c 和 r,表示当前最长回文字符串的中心和边界。数组p[max],p[i]表示以i为中心的回文字符串的长度之后对字符串从左向右处理,有更长的回文字符串就更新c 和 r。这是有如下结论:对于以i为中心的字符串,如果i < r,那么就有:p[i] >= min(p[2 * c - i], r - i)。然后再进行扩展。即可
根据实现后得到的p数组和字符串的对应关系:#a#s#s#d#010121010

贴Manacher算法的模板:

Manacher算法:        // 将S转换成T的预处理// 比如,S = "abba", T = "^#a#b#b#a#$"// ^和$符号用来表示开始和结束,并且避免边界检查。string preProcess(string s){    int n = s.length();    if (n == 0) return "^$";    string ret = "^";    for (int i = 0; i < n; i++)        ret += "#" + s.substr(i, 1);    ret += "#$";    return ret;}string longestPalindrome(string s){    string T = preProcess(s);    int n = T.length();    int* P = new int[n];    int C = 0, R = 0;    for (int i = 1; i < n - 1; i++) {        int i_mirror = 2 * C - i; // 等于i' = C - (i-C)    P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0;    // 尝试扩展中心为i的回文    while (T[i + 1 + P[i]] == T[i - 1 - P[i]])        P[i]++;    // 如果中心为i的回文超越了R,根据已扩展的回文来调整中心    if (i + P[i] > R) {        C = i;        R = i + P[i];        }    }    // 找出P中的最大值    int maxLen = 0;    int centerIndex = 0;    for (int i = 1; i < n-1; i++) {        if (P[i] > maxLen) {            maxLen = P[i];            centerIndex = i;        }    }    delete[] P;    //返回最大回文子串    return s.substr((centerIndex - 1 - maxLen)/2, maxLen);}

###这道题的思路:

  • 先用Manacher算法处理字符串,把以左端点为起点的回文子串的右端点加入到a数组中,把以右端点为终点的回文子串的左端点加入到b数组中(这里充分利用了Manacher算法处理之后得到的p数组,根据p[i]可以变换出,以i为中心的回文字符串在原串中的起点和终点)。然后枚举左边是a[i]结尾的字符串,和右边是b[j]开始的字符串,再由p数组判断他们中间的那个字符串是否是回文串即可。
  • 可以说这个题是Manacher算法的变形,只有充分理解p数组的由来,才可能知道它具有的变形能力。
  • 编码时间花费了很久,在动手写代码之前一定要已经思考的非常透彻,毫无逻辑缺陷再动手,这样效率是最高的。

Code:

#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <set>#include <map>#include <vector>#include <queue>#include <iterator>#include <cmath>#include <cstring>#include <cstdlib>using namespace std;typedef long long LL;const int INF = 0x3fffffff, M = 10009;vector<int> a, b, p;string preprocess(string s){    string ret = "^";    for (int i = 0; i < s.size(); i++) {        ret += "#";        ret += s[i];    }    ret += "#$";    return ret;}vector<int> Manacher(string t){    vector<int> p;    int R = 0, z = 0;    for (int i = 1; i < t.size() - 1; i++) {        p.push_back(R > i ?  min(R - i, p[2 * z - i - 1]) : 0);        while (t[i + p [i - 1] + 1] == t[i - p[i - 1] - 1]) p[i - 1]++;        if (p[i - 1] + i > R) {            z = i;            R = p[i - 1] + i;        }        if (p[i - 1] >= 1) {            int l = (i - 1 - p[i - 1]) / 2+ 1;            int r = (i - 1+ p[i - 1]) / 2;            if (l == 1) a.push_back(r);            if (r == (t.size() - 3) / 2) b.push_back(l);        }    }    return p;}bool hw(int x, int y){    int temp = y - x - 1;    if (temp <= 0) return false;    if ( p[((x * 2) - 1 + (y * 2) - 1) / 2] >= temp        && (p[((x * 2) - 1 + (y * 2) - 1) / 2] - temp) % 2 == 0) return true;    return false;}int main(void){    int t;    cin >> t;    while (t--) {        a.clear();        b.clear();        p.clear();        string s;        cin >> s;        //for (int i = 0 ; i < 100000; i++) s += "as";        bool ans = false;        if (s. size() < 3) { cout << "No" << endl; continue; }        string T = preprocess(s);        p = Manacher(T);        //for (int i = 0; i < p.size() ; i++) cout << p[i] << " ";        for (int i = 0; i < a.size(); i++) {            for (int j = 0; j < b.size(); j++) {                if (a[i] < b[j]) {                    int x = a[i];                    int y = b[j];                    if (hw(x, y)) {                        ans = true;                        goto l1;                    }                }            }        }l1:     if (ans) cout << "Yes" << endl;        else cout << "No" << endl;    }    return 0;}
0 0