[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;
}

posted @ 2023-12-21 21:42  MoyouSayuki  阅读(13)  评论(0编辑  收藏  举报
:name :name