在说正解前先orz一下zy的神骗分算法——
枚举总长度——如果在1~i和n-i+1~n这一段字母acsii和相同则在做下一步判断
然后枚举判断啦。。。。居然只超时一个点(数据好和谐~~)!
回来说正解。
看到题解,好厉害的题目!
这题目有个好厉害的性质。我们用F[i]记下(i+1,n-i)的最大相同前缀后缀,那么F[i-1]<=F[i]+2
证明就用反证法,自己画了张拙图:
如果F[i-1]>F[i]+2,那么红色区域相同,也就是说F[i]可以变得更大。得证!
这样复杂度就变为O(n)了。
坑题还会卡hash,果断加上zy大法a掉
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define gethash(l,r) ((hash[(r)]-(long long)hash[(l)-1]*pw[(r)-(l)+1]%MaxQ+MaxQ)%MaxQ)
const int MaxP=(1e9)+7, MaxQ=(1e9)+9, Maxn=1000005;
int hash[Maxn], a[Maxn], pw[Maxn], ans, n, i, j;
int main(){
freopen("pre.in","r",stdin);
freopen("pre.out","w",stdout);
scanf("%d\n",&n);
for (i=1,pw[0]=1;i<=n;i++) pw[i]=(long long)pw[i-1]*MaxP%MaxQ;
for (i=1;i<=n;i++){
char ch=getchar(); a[i]=ch;
hash[i]=((long long)hash[i-1]*MaxP%MaxQ+a[i])%MaxQ;
a[i]+=a[i-1];
}
for (i=n/2,j=0;i>0;i--,j=min(n/2-i,j+2))
if ( a[i]==a[n]-a[n-i] && gethash(1,i)==gethash(n-i+1,n) ){
for (;j>=0;j--)
if ( a[i+j]-a[i]==a[n-i]-a[n-i-j] )
if ( gethash(i+1,i+j)==gethash(n-i-j+1,n-i) )
{ ans=max(i+j,ans); break; }
}
printf("%d\n",ans);
return 0;
}