P41.99 million Path to Trail Solution

Description

Luogu Portal

Solution

Good name.

A lazy dog like me must be looking directly at the simplified title!

The Title lets us find the number of discontinuous palindrome sub-sequences. We find that it is not very good, so we change our thinking to ask:

\[Number of Palindrome Subsequences (Continuable) - Number of Palindrome Substrings \]

It is easy to find the number of palindrome substrings, that is, the \(manacher\) board. Let's consider how to find the number of palindrome substrings.

Set point \(id\) to be the symmetric center of a subsequence. If \(S_{i-j} = S_{i + j}\), our answer will have one more choice. Assuming there are \(i\) choices for the symmetric center \(f_i = x\), then:

  1. \(i\) is a character, and the answer is \(2^{x + 1} - 1\). There are \(x + 1\) selected or unselected characters, including the symmetric center, so there are \(x + 1\) cases in common \(2^{x + 1}\), and one case minus the empty set is the answer.
  2. \(i\) In the middle of two characters, the answer is \(2^x-1\), that is, the symmetric center cannot be included.

From the discussion above, you can see that the symmetric center is between two characters, so we doubled the original string as \(manacher\), so the center must be the whole point.

So how do I find this \(f_i\)?

Construct the generation function:

\[F(x) = \sum\limits_{i = 0}^{|s| - 1}a_ix^i \]

Then let \(F(x)\) roll itself up, that is, \(F(x)^2\), either NTT or FFT.

It is not difficult to find that the coefficient of \(x^i\) in (F(x)^2\) is the number of symmetrical character pairs \(\frac{i}{2}\) in the original string.

It is also observed that only a and b are in the input string, and there is no correlation between the two characters, so consider them separately:

  1. For a, if \ (S_i = a\), then \ (A_i = 1\) and vice versa \ (A_i = 0\).
  2. For the same reason for b, if \ (S_i = b\), then \ (B_i = 1\) and vice versa \ (B_i = 0\).

We can calculate \(f_i) after we have worked out \(A) and \(B\).

\[f_i = A^2 + B^2 \]

Final count of the answers.

Code

The NTT I'm using here requires two modules. Be careful not to mix up QwQ when writing

#include <bits/stdc++.h>
#define ll long long
#define cl const ll

using namespace std;

namespace IO{
    inline ll read(){
        ll x = 0;
        char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x;
    }

    template <typename T> inline void write(T x){
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace IO;

const ll N = 3e5 + 10;
const ll mod = 998244353, Mod = 1e9 + 7;
const ll G = 3, Gi = 332748118;
ll n, m, ans1, ans2;
ll a[N], b[N], c[N], d[N], rev[N];
int p[N];
char s[N], t[N];

namespace NTT{
    ll lim, len;

    inline ll qpow(ll a, ll b, ll mod){
        ll res = 1;
        while(b){
            if(b & 1) res = res * a % mod;
            a = a * a % mod, b >>= 1;
        }
        return res;
    }

    inline void get_rev(cl n){
        lim = 1, len = 0;
        while(lim < n) lim <<= 1, ++len;
        for(int i = 0; i < lim; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (len - 1));
    }

    inline void ntt(ll A[], cl lim, cl type){
        for(int i = 0; i < lim; ++i)
            if(i < rev[i]) swap(A[i], A[rev[i]]);
        for(int mid = 1; mid < lim; mid <<= 1){
            ll Wn = qpow(type == 1 ? G : Gi, (mod - 1) / (mid << 1), mod);
            for(int i = 0; i < lim; i += (mid << 1)){
                ll w = 1;
                for(int j = 0; j < mid; ++j, w = w * Wn % mod){
                    ll x = A[i + j], y = w * A[i + j + mid] % mod;
                    A[i + j] = (x + y) % mod;
                    A[i + j + mid] = (x - y + mod) % mod;
                }
            }
        }
        if(type == 1) return;
        ll inv = qpow(lim, mod - 2, mod);
        for(int i = 0; i < lim; ++i) A[i] = A[i] * inv % mod;
    }

    inline void Mul(cl n, cl m, ll a[], ll b[]){
        get_rev(n + m);
        ntt(a, lim, 1), ntt(b, lim, 1);
        for(int i = 0; i < lim; ++i) a[i] = a[i] * b[i] % mod;
        ntt(a, lim, -1);
    }
}
using namespace NTT;

inline void manacher(){
    n = strlen(t + 1);
    s[0] = '#', s[(n << 1) + 1] = '*';
    for(int i = 1; i <= n; ++i)
        s[(i << 1) - 1] = '*', s[i << 1] = t[i];
    m = (n << 1) + 1;
    int mx = 0, id = 0;
    for(int i = 1; i <= m; ++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] <= m && s[i - p[i]] == s[i + p[i]]) ++p[i];
        if(i + p[i] > mx) id = i, mx = i + p[i];
    }
    for(int i = 1; i <= (n << 1) + 1; ++i) ans1 = (ans1 + (p[i] >> 1)) % Mod;
}

inline void solve(){
    for(int i = 1; i <= n; ++i){
        if(t[i] == 'a') a[i - 1] = c[i - 1] = 1;
        else b[i - 1] = d[i - 1] = 1;
    }
    Mul(n, n, a, c), Mul(n, n, b, d);
    for(int i = 0; i <= (n << 1); ++i) c[i] = (a[i] + b[i]) % mod;
    for(int i = 0; i <= (n << 1) - 2; ++i){
        if(i & 1) ans2 = (ans2 + qpow(2, (c[i] >> 1), Mod) - 1 + Mod) % Mod;
        else ans2 = (ans2 + qpow(2, (c[i] >> 1) + 1, Mod) - 1 + Mod) % Mod;
    }
    write((ans2 - ans1 + Mod) % Mod), puts("");
}

int main(){
    scanf("%s", t + 1);
    manacher();
    solve();
    return 0;
}

\[\_EOF\_ \]

Posted on Wed, 01 Dec 2021 14:49:10 -0500 by pesoto74