题意:
给出一个长度为n的串S,求满足下面条件的最大的L:
- L<=n/2
- S的L前缀和S的L后缀是循环同构的。
思路:
设前缀为
a
a
a,后缀为
b
b
b,如果
a
,
b
a,b
a,b循环同构,那么
a
,
b
a,b
a,b是由一个字符串加上两个
b
o
r
d
e
r
border
border形成的。
即如下图所示:
s
1
,
i
=
s
l
+
1
,
n
,
s
i
+
1
,
j
=
s
k
,
l
s_{1,i}=s_{l+1,n},s_{i+1,j}=s_{k,l}
s1,i=sl+1,n,si+1,j=sk,l
于是考虑枚举可行的
i
i
i,并对于每个
i
i
i求出满足条件的最大的
j
j
j。
我们设
f
i
=
j
f_i=j
fi=j。
那么可以得出一个结论:
f
i
≤
f
i
+
1
+
2
f_i\le f_{i+1}+2
fi≤fi+1+2 (证明显然)
然后就暴力枚举
j
j
j即可,摊下来复杂度
O
(
n
)
O(n)
O(n)。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1e6+5;
char s[N];
int n,f[N];
typedef unsigned long long Ull;
typedef long long ll;
const Ull bas=141;
const int mod=1e9+9;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
struct string_hash{
Ull pw[N],ss[N];
int pww[N],sss[N];
inline void init(){
pw[0]=pww[0]=1;
for(ri i=1;i<=n;++i)pw[i]=pw[i-1]*bas,pww[i]=mul(pww[i-1],bas);
for(ri i=1;i<=n;++i)ss[i]=ss[i-1]*bas+(s[i]-'0'+15),sss[i]=add(mul(sss[i-1],bas),s[i]-'0'+15);
}
inline Ull gethash1(int l,int r){return ss[r]-ss[l-1]*pw[r-l+1];}
inline int gethash2(int l,int r){return dec(sss[r],mul(sss[l-1],pww[r-l+1]));}
inline bool check(int l1,int r1,int l2,int r2){return gethash1(l1,r1)==gethash1(l2,r2)&&gethash2(l1,r1)==gethash2(l2,r2);}
}S;
int main(){
scanf("%d%s",&n,s+1);
S.init();
f[n>>1]=0;
int ans=0;
for(ri l1,r1,l2,r2,i=(n>>1)-1;~i;--i){
l1=i+1,r2=n-i;
for(r1=min(n>>1,i+1+f[i+1]+1),l2=n+1-r1;r1>=l1;--r1,++l2)if(S.check(l1,r1,l2,r2))break;
f[i]=r1-l1+1;
if(S.check(1,i,n-i+1,n))ans=max(ans,i+f[i]);
}
cout<<ans;
return 0;
}