题解:
每个位置的回文后缀形成
logn
log
n
个等差数列。
回文自动机多维护三个值:
diff,sans,slink
d
i
f
f
,
s
a
n
s
,
s
l
i
n
k
。
然后暴力跳
slink
s
l
i
n
k
链即可。
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+50,INF=0x3f3f3f3f;
char s[N];
int n,last,tot=1;
int son[N][27],len[N],diff[N],link[N],slink[N];
int sans1[N],sans2[N],f1[N],f2[N];
inline int getfail(int pos,int l) {
while(s[l]!=s[l-len[pos]-1]) pos=link[pos];
return pos;
}
int main() {
link[0]=1; len[1]=-1;
scanf("%s",s+1); n=strlen(s+1);
memset(f1,0x3f,sizeof(f1));
memset(f2,0x3f,sizeof(f2));
f2[0]=0;
for(int i=1;i<=n;i++) {
int c=s[i]-'a'+1;
int now=getfail(last,i);
if(!son[now][c]) {
len[++tot]=len[now]+2;
link[tot]=son[getfail(link[now],i)][c];
diff[tot]=len[tot]-len[link[tot]];
if(diff[tot]==diff[link[tot]]) slink[tot]=slink[link[tot]];
else slink[tot]=link[tot];
son[now][c]=tot;
} last=son[now][c];
for(int v=last;len[v];v=slink[v]) {
sans1[v]=f1[i-(len[slink[v]]+diff[v])];
sans2[v]=f2[i-(len[slink[v]]+diff[v])];
if(diff[v]==diff[link[v]])
sans1[v]=min(sans1[v],sans1[link[v]]), sans2[v]=min(sans2[v],sans2[link[v]]);
f1[i]=min(f1[i],sans2[v]+1);
f2[i]=min(f2[i],sans1[v]+1);
}
(f1[i]<INF)?printf("%d ",f1[i]):printf("-1 ");
(f2[i]<INF)?printf("%d\n",f2[i]):printf("-2\n");
}
}