[SHOI2011]双倍回文

首先我们发现一个双倍回文串当且仅当本身是一个回文串且左右两边都是回文串。

那么对于右边的回文串,到中心 (i) 时,Manacher 所记录的 maxr 一定大于 (i),如果满足这个条件,那就判断 (i)(i) 关于 mid 的对称串是否有交点,有交点就说明这是双倍回文串。

时间复杂度 (O(n))

#include <bits/stdc++.h>
#define reg register
#define ll long long
#define ull unsigned long long
#define rep(i,a,n) for(reg int (i)=(a);(i)<=(n);++(i))
#define per(i,a,n) for(reg int (i)=(a);(i)>=(n);(i)--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define debug(typ...) fprintf(stderr, typ)
using namespace std;
const int iINF=numeric_limits<int>::max();
const ll lINF=numeric_limits<ll>::max();
int fastin() {
  reg int x = 0, ch = getchar(), f = 0;
  while(!isdigit(ch)) (ch == '-') && (f = 1), ch = getchar();
  while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
  return f ? -x : x;
}
const int MAXN=5e5+10;
const int MAXM=1e6+10;
int n,f[MAXM];
char s[MAXN],ss[MAXM];
void work() {
  n=fastin(),scanf("%s",s+1);
  rep(i,1,n) ss[(i<<1)-1]='#',ss[i<<1]=s[i];
  n=(n<<1)+1,ss[n]='#';
  int r=0,mid=0,ans=0;
  for(reg int i=1;i<=n;i+=2) {
    if(i<r) f[i]=min(f[(mid<<1)-i],r-i);
    else f[i]=1;
    if(i<r&&i-f[i]<mid) ans=max(ans,(i-mid)<<1);
    while(i-f[i]>=1&&i+f[i]<=n&&ss[i-f[i]]==ss[i+f[i]]) ++f[i];
    if(i+f[i]>r) r=i+f[i],mid=i;
  }
  printf("%d
",ans);
}
signed main() {
  int _=1;
  // _=fastin();
  while(_--) work();
  return 0;
}
原文地址:https://www.cnblogs.com/Lonely-233/p/13893962.html