求母串中互相交的回文串对数。
回文树练习题。
求相交的不好求,但是我们很容易求出不相交的(精华所在!要学会逆向思维!)
用回文树求出在此处开头和结尾的回文串非别为多少,直接搞就可以了。
#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; }