题意
给定一个长度为n的小写字母串。问你有多少对相交的回文子串(包含也算相交)
相交的回文子串个数 \(mod\ 51123987\)Sol
求相交的回文子串不太好求
考虑用总数减去不相交的回文串个数 那么考虑求以一个点结尾的后缀回文串的贡献: 就是以它后面的点为开头的前缀回文串的个数 正反两遍回文树求一下就好了# include# define IL inline# define RG register# define Fill(a, b) memset(a, b, sizeof(a))using namespace std;typedef long long ll;IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z;}const int maxn(2e6 + 5);const int mod(51123987);int first[maxn], nxt[maxn], type[maxn], fa[maxn], deep[maxn], pre[maxn], len[maxn];int tot, last, ans, n;char s[maxn];IL void Upd(RG int &x, RG int y){ x += y; if(x >= mod) x -= mod;}IL int NewNode(){ first[++tot] = len[tot] = fa[tot] = deep[tot] = nxt[tot] = 0; type[tot] = -1; return tot;}IL void Init(){ first[1] = first[0] = nxt[1] = nxt[0] = 0, type[0] = type[1] = -1; fa[0] = fa[1] = 1, tot = 1, last = 0, len[1] = -1;}IL int Son(RG int u, RG int c){ for(RG int v = first[u]; v; v = nxt[v]) if(type[v] == c) return v; return 0;}IL void Link(RG int u, RG int v, RG int c){ nxt[v] = first[u], first[u] = v, type[v] = c;}IL void Extend(RG int pos, RG int c){ RG int p = last; while(s[pos - len[p] - 1] != s[pos]) p = fa[p]; if(!Son(p, c)){ RG int np = NewNode(), q = fa[p]; while(s[pos - len[q] - 1] != s[pos]) q = fa[q]; len[np] = len[p] + 2, fa[np] = Son(q, c); Link(p, np, c), deep[np] = deep[fa[np]] + 1; } last = Son(p, c);}int main(){ n = Input(), scanf(" %s", s + 1), Init(); for(RG int i = 1; i <= n; ++i){ Extend(i, s[i] - 'a'); pre[i] = deep[last], Upd(pre[i], pre[i - 1]); Upd(ans, deep[last]); } ans = (1LL * ans * (ans - 1) >> 1) % mod; reverse(s + 1, s + n + 1), Init(); for(RG int i = 1; i <= n; ++i){ Extend(i, s[i] - 'a'); Upd(ans, mod - 1LL * deep[last] * pre[n - i] % mod); } printf("%d\n", ans); return 0;}