[CF17E] Palisection 题解
[CF17E] Palisection 题解
思路
直接统计相交的字符串很难数,考虑正难则反。
用总共的回文串对数减去相离的回文串个数。
设总共有 \(tot\) 个回文串,用 manacher 跑出来每个位置的最大回文半径后,使用差分的技巧保存两个数组:
\(f_i\) 表示以 \(i\) 为开头的回文串个数,\(g_i\) 表示以 \(i\) 为结尾的回文串个数。
所以如果固定了两对相离回文串中第一个回文串的结尾,只需要让另一个回文串的开头在第一个结尾的后面,所以答案就是:
\[\binom{tot}{2} - \sum_{i = 1}^n f_i\sum_{j = i + 1}^ng_j
\]
可以用前缀和优化,时间复杂度 \(O(n)\)。
// Problem: Palisection
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-12-20 23:50:56
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int N = 4e6 + 10, mod = 51123987;
int n, d[N], f[N], g[N];
long long tot;
string s, tmp;
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> s;
tmp = "$#";
for(int i = 0; i < s.size(); i ++)
tmp += s[i], tmp += "#";
swap(tmp, s);
d[1] = 1;
for(int i = 2, l = 0, r = 0; i < s.size(); i ++) {
if(i <= r) d[i] = min(r - i + 1, d[r - i + l]);
while(s[i - d[i]] == s[i + d[i]]) d[i] ++;
if(i + d[i] - 1 >= r) r = i + d[i] - 1, l = i - d[i] + 1;
}
n = s.size();
for(int i = 1; i <= n; i ++) {
(tot += d[i] / 2);
f[i - d[i] + 1] ++, f[i + 1] --; // 以 i 为开头
g[i] ++, g[i + d[i]] --; // 以 i 为结尾
}
for(int i = 1; i <= n; i ++) {
f[i] = (f[i - 1] + f[i]) % mod;
g[i] = (g[i - 1] + g[i]) % mod;
}
for(int i = n; i >= 1; i --)
if(isalpha(s[i])) f[i] = (f[i + 2] + f[i]) % mod;
int ans = ((__int128)tot * (tot - 1) / 2) % mod; // mod 不是质数我谔谔
for(int i = 1; i <= n; i ++)
if(isalpha(s[i]))
ans = (ans - 1ll * g[i] * f[i + 2] % mod) % mod;
cout << (ans + mod) % mod << '\n';
return 0;
}