一、題目
二、解法
正難則反,用全部減去不交即可得到相交的情況數。
先跑一遍,可以差分出以每個位置開始和結束迴文串數量,然後我們掃一遍,用前面的和乘上當前的計入貢獻,注意我們只需要統計#
號位置處的貢獻。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 4000005;
const int MOD = 51123987;
#define ll long long
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,p[M],l[M],r[M];char s[M],t[M];
ll qkpow(ll a,int b)
{
ll res=1;
while(b>0)
{
if(b&1) res=res*a%MOD;
a=a*a%MOD;
b>>=1;
}
return res;
}
signed main()
{
n=read();
scanf("%s",s);
for(int i=0;i<n;i++)
{
t[2*i+1]=s[i];
t[2*i]='#';
}
t[2*n]='#';
n=2*n+1;
int c=0,R=0;
for(int i=0;i<n;i++)
{
p[i]=R>i?min(p[2*c-i],R-i+1):1;
while(i+p[i]<n && i-p[i]>=0 && t[i+p[i]]==t[i-p[i]])
p[i]++;
if(i+p[i]>R)
{
R=i+p[i]-1;
c=i;
}
}
ll ans=0,s=0;
for(int i=0;i<n;i++)
{
l[i-p[i]+1]++;l[i+1]--;
r[i]++;r[i+p[i]]--;
ans=(ans+p[i]/2)%MOD;
}
ans=ans*(ans-1)/2%MOD;
for(int i=0;i<n;i++)
{
l[i]+=l[i-1];r[i]+=r[i-1];
if(i%2) ans=(ans-s*l[i])%MOD,s=(s+r[i])%MOD;
}
printf("%lld\n",(ans%MOD+MOD)%MOD);
}