Cf17e palisation problem solution

Description

Luogu portal

Solution

A very interesting question.

When you see the palindrome substring, you first think of the manacher algorithm. emm... But what to do after writing manacher?

We find that finding intersecting palindrome substrings is very troublesome, so the direct wave is positive and difficult, and the disjoint is subtracted from the total number of palindrome substrings.

Next, consider how to find disjoint palindrome substrings.

We open two arrays \ (f_i \), \ (g_i \)\ (f_i \) indicates how many palindrome strings start with \ (I \), \ (g_i \) indicates how many palindrome strings end with \ (I \).

When we see the \ (\ color{blue} {prefix and} \) in the tag, we prefix \ (g_i \) and save it in \ (sum_i \), then \ (sum_i \) represents the number of palindrome substrings ending with \ (I \) and previous points. We find that the number of disjoint palindrome substrings is:

\[res = \sum\limits_{i = 1}^{n}{sum_i \times f_{i + 1}} \]

Subtract from the total.

So what about \ (f_i \) and \ (g_i \)?

We found that the \ (\ color{blue} {differential} \) in the label has not been used. The label is really easy to use. Consider using differential.

We have used the manacher algorithm to calculate the longest palindrome radius when each point is the center of the palindrome string, and set it as \ (p_i \) (\ (p_i \) is the palindrome radius of the new string after the expansion of the original string, and the length is the length of the palindrome string of the original string. If you don't understand it, you can learn manacher, which will not be repeated here).

We found that a radius \ (p_i \) will form many palindrome strings, which are:

\[i - p_i + 1\ \ \ \ \sim\ \ \ \ i\ \ \ \ \sim\ \ \ \ i + p_i - 1 \]

\[i - p_i + 2\ \ \ \ \sim\ \ \ \ i\ \ \ \ \sim\ \ \ \ i + p_i - 2 \]

\[i - p_i + 3\ \ \ \ \sim\ \ \ \ i\ \ \ \ \sim\ \ \ \ i + p_i - 3 \]

\[· \]

\[· \]

\[i - 1\ \ \ \ \sim\ \ \ \ i\ \ \ \ \sim\ \ \ \ i + 1 \]

That is, we have to + 1 for both \ (f_{i - p_i + 1} \sim f_i \) and \ (g_i \sim g_{i + p_i - 1} \).

At this time, we can solve it by difference, that is \ (f_{i - p_i + 1} + + \), \ (f_{i + 1} -- \), and for \ (g_{i} + + \), \ (g_{i + p_i} -- \).

It's OK to cycle through the statistical answer for the last time. It should be noted that now we have expanded the original string, so the increase of the cycle is 2.

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long

using namespace std;

const ll N = 4e6 + 10;
const ll mod = 51123987;
ll n, ans, tot, sum;
char s[N], a[N];
ll f[N], g[N], p[N];

inline void manacher(){
    s[0] = '*', s[(n << 1) + 1] = '#';
    for(ll i = 1; i <= n; ++i)
        s[(i << 1) - 1] = '#', s[i << 1] = a[i];
    n = (n << 1) + 1;
    ll mx = 0, id = 0;
    for(ll i = 1; i <= n; ++i){
        if(i < mx) p[i] = min(mx - i, p[(id << 1) - i]);
        else p[i] = 1;
        while(i - p[i] >= 1 && i + p[i] <= n && s[i - p[i]] == s[i + p[i]]) p[i]++;
        if(i + p[i] > mx) mx = i + p[i], id = i;
        tot = (tot + (p[i] >> 1)) % mod;
    }
}

signed main(){
    scanf("%lld%s", &n, a + 1);
    manacher();
    for(ll i = 1; i <= n; ++i){
        f[i - p[i] + 1]++, f[i + 1]--;
        g[i]++, g[i + p[i]]--;
    }
    for(ll i = 1; i <= n; ++i)
        f[i] += f[i - 1], g[i] += g[i - 1];
    ans = tot * (tot - 1) / 2 % mod;
    for(ll i = 2; i <= n - 2; i += 2){
        sum = (sum + g[i]) % mod;
        ans = (ans - sum * f[i + 2] % mod + mod) % mod;
    }
    printf("%lld\n", ans);
    return 0;
}

End

Posted by Bjblatz on Fri, 05 Nov 2021 14:45:46 -0700