hdu5340—Three Palindromes—(Manacher算法)——回文子串

Three Palindromes

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1948    Accepted Submission(s): 687

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 an single line contains a string S which only consist of lowercase English letters.1≤|s|≤20000

Output

For each case, output the "Yes" or "No" in a single line.

Sample Input

2

abc

abaadada

Sample Output

Yes

No

题意:给出一个字符串,问能否将字符串分为三段,并且每一段的是回文串。

思路:这题要用到manacher算法,不知道的可以看一下这篇博客:https://blog.csdn.net/dyx404514/article/details/42061017。

首先用manacher求出以每个点为中点的回文串的半径,然后,我们可以知道,要将字符串分为三段,那第一段一定包含第一个字符,第三段一定包含最后一个字符。然后判断第一个回文串和第三个之间剩下的字符是否构成回文串就行了。

所以,我们找到用manacher算法求出的所有回文串中,包含了第一个字符和和最后一个字符的有那些,然后两两配对,看看是否存在某一对,他们不重合,且之间剩下的字符也是回文串。

具体操作看代码:

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<string>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<stack>
  8 #include<queue>
  9 #define eps 1e-7
 10 #define ll long long
 11 #define inf 0x3f3f3f3f
 12 #define pi 3.141592653589793238462643383279
 13 using namespace std;
 14 const int maxn = 20007;
 15 char a[maxn],s_new[maxn<<1];
 16 int s_len[maxn<<1];
 17
 18 int Init() //manacher算法初始化(模板)
 19 {
 20     int len = strlen(a);
 21     s_new[0] = ‘@‘;
 22     int j = 1;
 23     for(int i=0; i<len; ++i) //在每个字符左右插入‘#‘
 24     {
 25         s_new[j++] = ‘#‘;
 26         s_new[j++] = a[i];
 27     }
 28     s_new[j++] = ‘#‘;
 29     s_new[j] = ‘\0‘;
 30     return j;
 31 }
 32
 33 void manacher(int len) //计算以每个点为中心的回文串的半径(模板)
 34 {
 35     int high = 0,flag = 0;
 36     for(int i=1; i<len; ++i)
 37     {
 38         if(i < high)
 39             s_len[i] = min(high-i+1 , s_len[2*flag-i]);
 40         else
 41             s_len[i] = 1;
 42
 43         while(s_new[i + s_len[i]] == s_new[i - s_len[i]])
 44             s_len[i]++;
 45
 46         if(i + s_len[i] - 1 > high)
 47         {
 48             high = i+ s_len[i] -1;
 49             flag = i;
 50         }
 51     }
 52     return;
 53 }
 54
 55 bool judge(int len) //判断是否可以分为3个回文串
 56 {
 57     int visit1[maxn<<1], visit2[maxn<<1], cnt1 = 0, cnt2 = 0;      //visit1用来存储所有包含第一个字符的字符串的中点下标
 58     //visit2用来存储包含最后一个字符串的中点下标
 59
 60     for(int i=1; i<len; ++i) //遍历一遍,找到存入visit数组中
 61     {//因为以 i 为中点的回文串的长度是s_len[i]-1,所以还要判断一下这个回文串长度是否为 0;
 62         if(i - s_len[i] + 1 == 1 && s_len[i] - 1 > 0)
 63             visit1[cnt1++] = i;
 64         if(i + s_len[i] - 1 == len-1 && s_len[i] - 1 > 0)
 65             visit2[cnt2++] = i;
 66     }
 67     bool flag = false;
 68     int mid;
 69     for(int i=0; i<cnt1; ++i) //for循环的嵌套用来让三段中,第一段和第三段两两配对
 70     {
 71         for(int j=cnt2-1; j>=0; --j)
 72         {
 73             if(visit1[i] + s_len[visit1[i]] - 1 < visit2[j] - s_len[visit2[j]] + 1)           //选出的两段不能有重合,有重合表示中间没字符了
 74             {
 75                 mid = ( (visit1[i] + s_len[visit1[i]] - 1) + (visit2[j] - s_len[visit2[j]] + 1) ) / 2;            //然后取两段中间剩余字符的中点
 76                 if(mid - s_len[mid] + 1 <= visit1[i] + s_len[visit1[i]] && s_len[mid]-1 > 0)             //判断以中点为中心的回文串是否完全覆盖了中间所有的字符
 77                 {
 78                     flag = true; //若覆盖了,则表示可以分成三段回文串
 79                     break; //就不需要再继续查找了
 80                 }
 81             }
 82         }
 83         if(flag) break;
 84     }
 85     return flag;
 86 }
 87
 88 int main()
 89 {
 90     int t;
 91     cin>>t;
 92     while(t--)
 93     {
 94         scanf("%s",a);
 95         int len = Init();
 96         manacher(len);
 97
 98         bool T_or_F = judge(len);
 99         if(T_or_F)
100             cout<<"Yes\n";
101         else
102             cout<<"No\n";
103     }
104     return 0;
105 }

原文地址:https://www.cnblogs.com/tuyang1129/p/9365428.html

时间: 2024-10-08 01:19:10

hdu5340—Three Palindromes—(Manacher算法)——回文子串的相关文章

Manacher算法----最长回文子串

题目描述 给定一个字符串,求它的最长回文子串的长度. 分析与解法 最容易想到的办法是枚举所有的子串,分别判断其是否为回文.这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些的子串,那么对子串的回文判断其实是不需要的.同时,奇数和偶数长度还要分别考虑. Manacher算法可以解决上述问题,并在O(n)时间复杂度内求出结果.下面我们来看一下Manacher算法. 首先,为了处理奇偶的问题,在每个字符的两边都插入一个特殊的符号,这样所有的奇数或偶数长度都转换为奇数长度.比

[hiho 01]最长回文子串、Manacher算法

题目描述 - 基础方法:枚举子串,判断是否为回文串. - 改进:枚举中间位置,向两侧拓展. - 再改进:利用以前的信息,使得不用每个新位置都从长度1开始拓展. - 优化:将字符串预处理为奇数长度以避免考虑条件分支. - 再优化:开头加入特殊字符避免考虑边界. Manacher 算法: id 是中心点,mx 是其边界.P[i] 表示以 i 为中心的最长回文子串的折半长度. 只要 i < mx, 以 i 为中心的回文子串就可以不必从长度1开始找,而从min{P[j], mx - i}开始(其中j为i

Manacher算法--O(n)内求回文子串

昨天做了leetcode里的     Longest Palindromic Substring ,一开始用动态规划O(N^2),不管怎么改都超时了...于是在大神的帮助下,找到了传说中的Manacher算法,居然能在O(n)内求出来,瞬间给跪了. 本屌认为,这个算法主要是充分的利用了以前的匹配的结果,来起到了降低时间复杂度的作用,这点跟KMP算是有点类似.在预处理时有个小技巧就是将第0,1为设为"$#",后面每隔一位加一个"#",这样既能够防止数组越界问题又能够,

Petrozavodsk Winter-2013. Ural FU Contest Problem D. Five Palindromes manacher、一个串切割成5个回文子串、优化

Ural Federal University Contest, SKB Kontur Cup Petrozavodsk Winter Training Camp, Saturday, February 2, 2013 Problem D. Five Palindromes Input file: input.txt Output file: output.txt Time limit: 2 seconds (3 seconds for Java) Memory limit: 256 mebib

O(n)回文子串(Manacher)算法

O(n)回文子串(Manacher)算法 资料来源网络 参见:http://www.felix021.com/blog/read.php?2040 问题描述: 输入一个字符串,求出其中最大的回文子串.子串的含义是:在原串中连续出现的字符串片段.回文的含义是:正着看和倒着看相同,如abba和yyxyy. 解析: 这里介绍O(n)回文子串(Manacher)算法 算法基本要点:首 先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号.比

O(n) 求最长回文子串的 Manacher 算法

Manacher是一个可以在O(n)的时间内求出一个长度为n的字符串的算法. 以为回文子串有偶数长度,也有奇数长度,分别处理会很不方便. 所以在每两个字符中间插入一个无关字符,如‘#’,这样所有的回文子串都变为奇数长度. 两端在添加不同的无关字符防止匹配时越界. 如: abba 变成 $#a#b#b#a#& 预处理代码: void Prepare() { l = strlen(Str); S[0] = '$'; for (int i = 0; i <= l - 1; i++) { S[(i

计算字符串的最长回文子串 :Manacher算法介绍

在介绍算法之前,首先介绍一下什么是回文串,所谓回文串,简单来说就是正着读和反着读都是一样的字符串,比如abba,noon等等,一个字符串的最长回文子串即为这个字符串的子串中,是回文串的最长的那个. 计 算字符串的最长回文字串最简单的算法就是枚举该字符串的每一个子串,并且判断这个子串是否为回文串,这个算法的时间复杂度为O(n^3)的,显然无法令人 满意,稍微优化的一个算法是枚举回文串的中点,这里要分为两种情况,一种是回文串长度是奇数的情况,另一种是回文串长度是偶数的情况,枚举中点再判断是否 是回文

[hdu3068 最长回文]Manacher算法,O(N)求最长回文子串

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 题意:求一个字符串的最长回文子串 思路: 枚举子串的两个端点,根据回文串的定义来判断其是否是回文串并更新答案,复杂度O(N3). 枚举回文串的对称轴i,以及回文半径r,由i和r可确定一个子串,然后暴力判断即可.复杂度O(N2). 在上一步的基础上,改进判断子串是否是回文串的算法.记fi(r)=(bool)以i为对称轴半径为r的子串是回文串,fi(r)的值域为{0, 1},显然fi(r)是关于r

最长回文子串之Manacher算法

以Hihocoder 1032为例. manacher算法: 设一个数组p,p[i]表示以第i个字符为中心的最大半径,最大的p[i]就是最长的回文子串了. 不过这样要用两个循环,时间复杂度是(n*n). 1 int solve(){ 2 int len = strlen(str), ans = 0; 3 for(int i = 0; i < len; i ++){ 4 for(int j = 0; i-j>=0 && i+j < len; j++){ 5 if(str[i

Manacher&#39;s algorithm: 最长回文子串算法

Manacher 算法是时间.空间复杂度都为 O(n) 的解决 Longest palindromic substring(最长回文子串)的算法.回文串是中心对称的串,比如 'abcba'.'abccba'.那么最长回文子串顾名思义,就是求一个序列中的子串中,最长的回文串.本文最后用 Python 实现算法,为了方便理解,文中出现的数学式也采用 py 的记法. 在 leetcode 上用时间复杂度 O(n**2).空间复杂度 O(1) 的算法做完这道题之后,搜了一下发现有 O(n) 的算法.可惜