Luogu

分析

先对每个串跑一遍 Manacher。设求出的分别为 $f_i$ 和 $g_i$。

这时第一、二类的最长长度即为 $\max\left\{f_i\right\}$ 和 $\max\left\{g_i\right\}$。

考虑第三类的最长长度怎么求。枚举中点 $i$,发现此时的扭动串变成了三段:一段是某个串中 $i$ 向外扩展出的回文串,一段是 $A$ 中继续向左扩展出的串,一段是 $B$ 中继续向右扩展出的串。

容易发现后两段相反,二分答案并利用哈希 check() 即可。

代码

// ===================================
//   author: M_sea
//   website: http://m-sea-blog.com/
// ===================================
#include <bits/stdc++.h>
#define re register
using namespace std;
typedef unsigned long long ull;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=200000+10;
const ull BASE=19491001;

int n; char a[N],b[N];

ull pw[N],ha[N],hb[N];
inline ull gethash(int op,int l,int r) {
    if (op==1) return ha[r]-ha[l-1]*pw[r-l+1];
    if (op==2) return hb[l]-hb[r+1]*pw[r-l+1];
}

int f[N],g[N]; char c[N];
inline void change(char* s) {
    for (re int i=1;i<=n;++i) c[i]=s[i];
    for (re int i=1;i<=n;++i) s[i<<1]=c[i],s[i<<1|1]='#';
    s[0]='?',s[1]='#',s[(n+1)<<1]='\0';
}
inline void manacher(char* s,int* f) {
    for (re int i=1,mid,mr=0;i<=n;++i) {
        f[i]=i<mr?min(f[(mid<<1)-i],mr-i):1;
        while (s[i-f[i]]==s[i+f[i]]) ++f[i];
        if (i+f[i]>mr) mid=i,mr=i+f[i];
    }
}

inline int calc(int x,int y) {
    if (x<1||y>n||a[x<<1]!=b[y<<1]) return 0;
    int L=1,R=min(x,n-y+1);
    while (L<R) {
        int mid=(L+R+1)>>1;
        if (gethash(1,x-mid+1,x)==gethash(2,y,y+mid-1)) L=mid;
        else R=mid-1;
    }
    return L;
}

int main() {
    n=read(); scanf("%s%s",a+1,b+1);
    pw[0]=1; for (re int i=1;i<=n;++i) pw[i]=pw[i-1]*BASE;
    for (re int i=1;i<=n;++i) ha[i]=ha[i-1]*BASE+a[i];
    for (re int i=n;i>=1;--i) hb[i]=hb[i+1]*BASE+b[i];
    change(a),change(b),n=n<<1|1,manacher(a,f),manacher(b,g);
    int ans=0;
    for (re int i=1;i<=n;++i) ans=max(ans,f[i]-1);
    for (re int i=1;i<=n;++i) ans=max(ans,g[i]-1);
    for (re int i=1;i<=n;++i) { int L,R;
        L=(i-f[i])/2+1,R=(i+f[i])/2-1;
        ans=max(ans,f[i]-1+(calc(L-1,R)<<1));
        L=(i-g[i])/2+1,R=(i+g[i])/2-1;
        ans=max(ans,g[i]-1+(calc(L,R+1)<<1));
    }
    printf("%d\n",ans);
    return 0;
}
最后修改:2021 年 03 月 24 日 03 : 04 PM