HDU - 3068 - 最长回文

先上题目:

最长回文

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7899    Accepted Submission(s): 2703


Problem Description
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
 

 

Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
 

 

Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
 

 

Sample Input
aaaa
abab
 

 

Sample Output
4
3
 
  做法:使用manacher算法求最长回文串。这玩意有一个优点,可以统一处理奇数或者偶数的回文串,不用分开讨论。
  首先将每一个字符用一个分隔符隔开(例如'#'),当然,字符串的开头和结尾都要加分隔符。然后再求出为一个位置为中间的最长回文串一条臂的长度p[i],那么原串中以这一个字符为中心的的回文的长度等于p[i]-1。
  具体实现过程看代码。值得注意的是根据manacher求出的st并不是最长回文串的起始位置,所以需要再扫描一遍p[]求出最大值。
 
上代码:
 
 1 #include <cstdio>
 2 #include <cstring>
 3 #define min(x,y) (x < y ? x : y)
 4 #define MAX 110002
 5 using namespace std;
 6 
 7 char s[MAX<<1],c[MAX];
 8 int p[MAX<<1];
 9 
10 int get(int &k){
11     s[0]='$';s[1]='#'; k=2;
12     while((s[k]=getchar())!=EOF) {
13         if(s[k]=='\n'){
14             s[k]='\0';
15             return k;
16         }
17         s[++k]='#';
18         k++;
19     }
20     return EOF;
21 }
22 
23 int main()
24 {
25     int k;
26     while(get(k)!=EOF){
27         int mx=0,id=0;
28         if(k==2) continue;
29         //memset(p,0,sizeof(int)*(k+1));
30         p[0]=p[1]=p[2]=0;
31         for(int i=1;i<k;i++){
32             p[i]= mx > i ? min(p[2*id-i],mx-i) : 1;
33             while(s[i+p[i]]==s[i-p[i]]) p[i]++;
34             if(i+p[i]>mx){
35                 mx=i+p[i];
36                 id = i;
37             }
38         }
39         id=0;
40         for(int i=0;i<k;i++){
41             if(p[id]<p[i]) id=i;
42         }
43         printf("%d\n",p[id]-1);
44     }
45     return 0;
46 }
/*3068*/

 

 

posted @ 2014-08-05 16:54  海拉鲁的林克  阅读(195)  评论(0编辑  收藏  举报