# 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

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

Sample Input
2
abc

Sample Output
Yes
No

  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 }

posted @ 2018-07-25 13:18  特务依昂  阅读(234)  评论(0编辑  收藏  举报