1. 程式人生 > >hdu5340—Three Palindromes—(Manacher算法)——回文子串

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

scrip efi HERE ive http frame == sof iss

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 T20 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 }

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