求母串中互相交的回文串对数。
回文树练习题。
求相交的不好求,但是我们很容易求出不相交的(精华所在!要学会逆向思维!)
用回文树求出在此处开头和结尾的回文串非别为多少,直接搞就可以了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int Mod=51123987;
const int Maxn=2000005;
char S[Maxn];
int fail[Maxn],num[Maxn],s1[Maxn],s2[Maxn];
int a[Maxn],K[Maxn],next[Maxn],len[Maxn];
int n,c,t,p,last,i,st,ans;
int fd(int x,int c){
for (int i=a[x];i;i=next[i])
if (K[i]==c) return i;
return 0;
}
int newnode(int l){
len[st] = l;
return st++;
}
void init(){
st = 0;
S[0] = '#';
newnode(0);
newnode(-1);
fail[0] = 1;
fail[1] = 0;
last = 0;
}
int get_fail(int x,int n){
while (S[n-len[x]-1]!=S[n]) x=fail[x];
return x;
}
void work(int s[]){
memset(a,0,sizeof(a));
init();
for (i=1;i<=n;i++){
c = S[i]-'a';
t = get_fail(last,i);
if (!fd(t,c)){
p = newnode(len[t]+2);
fail[p] = fd( get_fail( fail[t], i ), c );
next[p] = a[t]; a[t] = p; K[p] = c;
num[p] = num[fail[p]]+1;
}
last = fd(t,c);
s[i] = num[last];
}
}
int main(){
freopen("17E.in","r",stdin);
freopen("17E.out","w",stdout);
scanf("%d\n",&n);
scanf("%s",S+1);
work(s1);
for (i=1;i<=n/2;i++)
swap(S[i],S[n-i+1]);
work(s2);
LL N = 0, NN;
for (i=1;i<=n;i++)
N = N+(LL)s1[i];
NN = N-1;
if (N&1) NN>>=1; else N>>=1;
for (i=1;i<=n/2;i++)
swap(s2[i],s2[n-i+1]);
for (i=n;i>0;i--)
s2[i] = (s2[i]+s2[i+1])%Mod;
for (i=1;i<n;i++)
ans = (ans+(LL)s1[i]*s2[i+1]%Mod)%Mod;
ans = ( (LL)(NN%Mod)*(N%Mod)%Mod-ans+Mod )%Mod;
printf("%d\n",ans);
return 0;
}