D2. Prefix-Suffix Palindrome (Hard version)-----------------------------------思维(马拉车)

D2. Prefix-Suffix Palindrome (Hard version)-----------------------------------思维(马拉车)_第1张图片
D2. Prefix-Suffix Palindrome (Hard version)-----------------------------------思维(马拉车)_第2张图片

题意:
给定一个字符串s。
求一个最长回文子串t=a+b (a是s的前缀,b是s的后缀)
解析:

首先遍历前后缀相同的一部分,如果没有剩余一段,那么整个串就是最长回文子串

如果有剩余的一段为[l,r],就对[l,r]这段跑马拉车 求出这部分最大前缀回文或最大后缀回文即可 设为x
最长回文子串就为: [0,l]+x+[r+1,n]

#include<bits/stdc++.h>
#define Min(a,b) a>b?b:a
using namespace std;
const int N=2e6+10000;
char s[N],str[N];
int p[N];
int len,n,f;
int ans;
int t;
void init(int l,int r)
{
	int k=0;
	str[k++]='@';
	for(int i=l;i<=r;i++)
	{
		str[k++]='#';
		str[k++]=s[i];
	}
	str[k++]='#';
	len=k;
	str[k]='\0';
	
}
void mlc()
{
	int mx=0,id=0;
	p[0]=0;
	for(int i=1;i<len;i++)
	{
		if(i<mx) p[i]=min(mx-i,p[2*id-i]);
		else p[i]=1;
		while(str[i-p[i]]==str[i+p[i]]) p[i]++;
		if(i+p[i]>mx)
		{
			mx=i+p[i];
			id=i;
		}
		if(p[i]==i)
		{
			if(ans<p[i])
			{
				ans=p[i]-1;
				f=1;
			}
		}
		if(p[i]+i==len)
		{
			if(ans<p[i])
			{
				ans=p[i]-1;
				f=2;
			}
		}
	}
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		f=0;
		ans=0;
		scanf("%s",s);
		 n=strlen(s);
		int l=0,r=n-1;
		while(s[l]==s[r]&&l<r)//去除相同的前缀和后缀
		{
			l++;
			r--;
		}
		if(l>=r)
		{
			cout<<s<<endl;
			continue;
		}
		init(l,r); 
		mlc();
		for(int i=0;i<l;i++) printf("%c",s[i]);
		if(f==1) //输出[l,r]这一段的最长回文前缀部分
		{
			for(int i=l,j=0;j<ans;i++,j++)  printf("%c",s[i]);
		}
		else//输出[l,r]这一段的最长回文后缀部分
		{
			for(int i=r-ans+1;i<=r;i++)  printf("%c",s[i]);
		}
		//输出剩下的一段
		for(int i=r+1;i<n;i++)  printf("%c",s[i]);
		puts("");
	}
 } 

你可能感兴趣的:(马拉车,思维,Codeforces)