CF17E Palisection(manacher)
文章目录
【注意】最后更新于 February 8, 2020,文中内容可能已过时,请谨慎使用。
题目链接
题意简述
给你一个字符串,求有多少对相交的回文子串。(包含算作相交,自交不算)
字符串长度小于等于 $2\times 10^6$。
简要做法
首先 manacher 求出每个中心的最长回文串半径。
然后,通过差分可以求出每个位置作为左端点 / 右端点各有多少个回文串(知道每个中心的半径之后就相当于区间加),记为 $l_i$, $r_i$。
最后,我们把问题转化为求不相交的回文子串对数,这样的话就是 $\sum\limits_{i = 2}^n\sum\limits_{j=1}^{i-1}l_ir_j$,预处理一下 $r$ 的前缀和就可以算了。
参考代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2000010;
const int mod = 51123987;
char s[N << 1];
int n, p[N << 1], mid, rt, l[N], r[N], pre[N], ans;
int main()
{
int i;
scanf("%d%s", &n, s + 1);
s[0] = '$';
for (i = n * 2 + 1; i >= 1; --i)
{
if (i & 1) s[i] = '#';
else s[i] = s[i / 2];
}
mid = rt = 1;
for (i = 2; i <= n * 2 + 1; ++i)
{
p[i] = min(rt - i, p[mid * 2 - i]);
while (s[i + p[i] + 1] == s[i - p[i] - 1]) ++p[i];
if (i + p[i] > rt)
{
mid = i;
rt = i + p[i];
}
++l[(i - p[i] + 1) >> 1];
--l[(i >> 1) + 1];
++r[(i + 1) >> 1];
--r[(i + p[i] + 1) >> 1];
ans = (ans + (p[i] + 1) / 2) % mod;
}
ans = (ll) ans * (ans - 1) % mod * (mod + 1) / 2 % mod;
for (i = 1; i <= n; ++i)
{
l[i] += l[i - 1];
r[i] += r[i - 1];
pre[i] = (pre[i - 1] + r[i]) % mod;
ans = (ans - (ll) l[i] * pre[i - 1] % mod + mod) % mod;
}
cout << ans;
return 0;
}
评论正在加载中...如果评论较长时间无法加载,你可以 搜索对应的 issue 或者 新建一个 issue 。