对于两个字符串 ,若能将 的一个后缀整体移动到 的前面则称它们是循环同构的。
给定一个长 的字符串,求最大的 使得 和 是循环同构的。
。
第一步就没想到。
考虑两个串循环同构当且仅当一个串是 而另一个串是 ,故有 。
那么枚举 的长度,然后问题就变成求头尾都去掉 个字符后的 border。
设 表示头尾都去掉 个字符后的 border,那么显然有 ,那么 从大往小每次暴力往前跑找到第一个合法即可,实现注意需要双哈希。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int S=1000005;
const int bse=31,p1=1000000007,p2=998244353;
int n;
char a[S];
int pw1[S],pw2[S];
int h1[S],h2[S];
inline int cal1(int l,int r)
{
return (h1[r]-1ll*pw1[r-l+1]*h1[l-1]%p1+p1)%p1;
}
inline int cal2(int l,int r)
{
return (h2[r]-1ll*pw2[r-l+1]*h2[l-1]%p2+p2)%p2;
}
inline bool chk(int l,int r,int k)
{
if(k==0) return true;
return cal1(l,l+k-1)==cal1(r-k+1,r)&&
cal2(l,l+k-1)==cal2(r-k+1,r);
}
int main()
{
scanf("%d%s",&n,a+1);
pw1[0]=pw2[0]=1;
for(int i=1;i<=n;i++)
{
pw1[i]=1ll*pw1[i-1]*bse%p1;
pw2[i]=1ll*pw2[i-1]*bse%p2;
h1[i]=(1ll*h1[i-1]*bse+a[i]-'a'+1)%p1;
h2[i]=(1ll*h2[i-1]*bse+a[i]-'a'+1)%p2;
}
int ans=0;
for(int l=n/2,r=n/2+1+(n&1),len=0;l>=1;l--,r++)
{
if(chk(1,n,l)) ans=max(ans,l+len);
if(len+2<=(r-l+1)/2&&chk(l,r,len+2)) len+=2;
else if(len+1<=(r-l+1)/2&&chk(l,r,len+1)) len++;
while(!chk(l,r,len)) len--;
}
printf("%d\n",ans);
return 0;
}