hdu 5340 Manachers + 枚举



题意:给你一个字符串问能否拆分为三个回文字符串?能就输出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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-30 13:26:36

hdu 5340 Manachers + 枚举的相关文章

hdu 5340 最长回文子串变形

http://acm.hdu.edu.cn/showproblem.php?pid=5340 Problem Description Can we divided a given string S into three nonempty palindromes? Input First line contains a single integer T≤20 which denotes the number of test cases. For each test case , there is

hdu 5340 Three Palindromes(字符串处理+ 回文)

hdu 5340 Three Palindromes 问题描述 判断是否能将字符串S分成三段非空回文串. 输入描述 第一行一个整数T,表示数据组数.T \leq 20T≤20 对于每一个组,仅包含一个由小写字母组成的串.1 \leq |S| \leq 200001≤∣S∣≤20000 输出描述 对于每一组,单行输出"Yes" 或 "No". 输入样例 2 abc abaadada 输出样例 Yes No 题目大意:给出一个字符串,判断,是否能将其分成三个不为空的回文

HDU 5340 Three Palindromes( 折半枚举+Manacher+记录区间 )

Three Palindromes Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 809    Accepted Submission(s): 240 Problem Description Can we divided a given string S into three nonempty palindromes? Input F

hdu 5340 Three Palindromes 【Manacher】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5340 题意:判断一个字符串能否分为三个回文串 解法:manacher枚举第一第三个,判断第二个. 代码: #include <stdio.h> #include <ctime> #include <math.h> #include <limits.h> #include <complex> #include <string> #inclu

HDU - 5340 Three Palindromes(manacher算法)

http://acm.hdu.edu.cn/showproblem.php?pid=5340 题意 判断是否能将字符串S分成三段非空回文串 分析 manacher预处理出前缀和后缀回文的位置, 枚举第一个回文串和第三个回文串,这样得到第二个回文串的区间,找中点,因为manacher处理后所有的回文串长度都是奇数,然后根据中点的回文半径判断中间部分是否回文即可, 复杂度o(n2).至于n2复杂度为什么能水过去..不是很懂 #include<iostream> #include<cmath&

HDU 6103 Kirinriki 枚举长度 尺取法

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6103 题目描述: 定义两个相同长度的字符串的值为首尾开始字符串的ASCII相减, 求一个字符串中任取两个相同长度的不重叠的值不超过m的最大长度 解题思路: 求连续区间不超过某一个上限或者不低于某个下限的应该用尺取法 ,复杂度为O(n),  本题n是5000所以O(n^2)可行, 枚举前缀和后缀(通过枚举前缀, 再将字符串翻转枚举前缀进行), 再进行尺取 代码:  代码中有注释 #include <

HDU 4068 dfs枚举

SanguoSHA Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 944    Accepted Submission(s): 520 Problem Description Sanguosha has a singled version. Two players each select N heroes and start fight

Hdu 5340 Three Palindromes 最大回文串 Manacher

Three Palindromes Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 80    Accepted Submission(s): 21 Problem Description Can we divided a given string S into three nonempty palindromes? Input Fir

HDU 5319 Painter(枚举)

Painter Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 745    Accepted Submission(s): 345 Problem Description Mr. Hdu is an painter, as we all know, painters need ideas to innovate , one day,