HYSBZ 2342-双倍回文(Manacher算法应用)

 

在这里插入图片描述

Input

输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。

Output

输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。
Sample Input
16

ggabaabaabaaball
Sample Output
12
HINT

N<=500000
(详情看注释,因为没有理解Manacher算法数组的含义,这道题没做出来,太菜了。)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=2e6+10;
int n,m,f[maxn],g[maxn];
char a[maxn],s[maxn];
int main(void)
{
	while(cin>>n)
	{
		int i,r,p;
		scanf("%s",a+1);
		for(int i=1;i<=n;i++) 
		 s[i<<1]=a[i],s[i<<1|1]='#';
		s[0]='$',s[1]='#',s[m=(n+1)<<1]='@';
		
		for(r=p=0,f[1]=1,i=2;i<m;i++)
		{
			for(f[i]=r>i?min(r-i,f[p*2-i]):1;s[i-f[i]]==s[i+f[i]];f[i]++);
			if(i+f[i]>r) r=i+f[i],p=i;
		}
		int ans=0;
		//串的中心显然是填充字符,所以i初始值为3,并且i+=2。 
        for(int i=3;i<m;i+=2)
		{
		   int len=f[i]-1;
           while(len>3)
           { 
           	 if(len%4==0)
           	 {
           	 	//如果比当前答案小直接跳出循环,节省时间 
           	     if(len<ans) break;
           	     //找到串的左端 
	           	 int l=i-len;
	           	 
				 int r=i;
				 //找到左边串的中心 
	           	 int m=(l+r)/2;
	           	 //如果左边的串能覆盖到i,保证左边的串也为回文串。 
	           	 if(m+f[m]-1>=i)
	           	  ans=max(ans,len);            	 	
			 }
	         len-=2;
		   }
			
		}  
		printf("%d\n",ans);
	
	
	
	}
	
	
	return 0;
 } 
 /*
8
aaaaaaaa
12
abbaabbaabba
12
abaabaabaaba 
*/
posted @ 2019-03-17 19:27  鸟人呀  阅读(129)  评论(0编辑  收藏  举报