给n个数,求满足条件的子串的最长长度。
条件:整个数字串可分为三段,前两段和后两段均为回文串。
解法:先用manacher算法求出各个位置为中心的回文长度,然后分别枚举前两段和后两段的对称中心,即枚举中间那段的长度。由于manacher算法求出来的每个中心的回文长度是最长的,因此只要有后两段的回文串的最长回文半径大于等于所枚举的长度,就可以更新答案。
时间复杂度为O(n)
关于manacher算法
#include<iostream> #include<cstdio> #include<cmath> #include<map> #include<set> #include<algorithm> #include<queue> #include<stack> #include<cstdlib> #include<cstring> #include<vector> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef long long LL; typedef unsigned long long uLL; typedef __int64 LI; typedef unsigned __int64 uLI; typedef unsigned int uI; typedef double db; #define maxn 100005 #define inf 0x3f3f3f3f int n,p[maxn<<1]; int a[maxn<<1],b[maxn]; void Manacher(){ int i,mx=0,id; for(i=1;i<=n;++i) { if(mx>i) p[i]=min(mx-i,p[2*id-i]); else p[i]=1; for(;a[i+p[i]]==a[i-p[i]];p[i]++); if(p[i]+i>mx){ mx=p[i]+i; id=i; } } } int main() { int i,j,ca=1,t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i=1;i<=n;++i) scanf("%d",&b[i]); a[0]=-2,a[1]=-1; for(i=1;i<=n;++i){ a[i*2]=b[i]; a[i*2+1]=-1; } n=2*n+1; Manacher(); int ans=-1; for(i=1;i<=n;i+=2) for(j=i+p[i]-1;j-i+1>ans;j-=2) if(p[j]>=j-i+1) ans=j-i+1; printf("Case #%d: %d\n",ca++,(ans-1)/2*3); } return 0; }