ABC214F - Substrings

問題

https://atcoder.jp/contests/abc214/tasks/abc214_f

略説

部分列dp

同じ文字列ならばindex列が辞書順最小になるように選択していくことで重複を回避する

nxt[i][j] := i以降で最初に出現する文字jのindex

dp[i] := i文字目までの文字列の種類数 (i文字めは必ず使う)

dp[nxt[i][j] (隣合うときは更にもう一つ進める)] += dp[i]

ACコード
#include <bits/stdc++.h>
using namespace std;

template <unsigned int MOD>
struct Modint {
    unsigned int x;
    constexpr Modint(): x(0) {}
    template <typename T>
    constexpr Modint(T _x) noexcept : x((_x%=MOD)<0 ? _x+MOD : _x) {}
    constexpr Modint inv() const noexcept {
        long long a = x, b = MOD, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b;
            swap(a, b);
            u -= t * v;
            swap(u, v);
        }
        return Modint(u);
    }
    constexpr Modint operator+() const noexcept {return *this;}
    constexpr Modint operator-() const noexcept {return Modint()-*this;}
    constexpr Modint &operator++() noexcept {
        if (++x == MOD) x = 0;
        return *this;
    }
    constexpr Modint &operator--() noexcept {
        if (x-- == 0) x += MOD;
        return *this;
    }
    constexpr Modint operator++(int) noexcept {
        Modint res = *this;
        ++*this;
        return res;
    }
    constexpr Modint operator--(int) noexcept {
        Modint res = *this;
        --*this;
        return res;
    }
    constexpr Modint &operator+=(const Modint &y) noexcept {
        if ((x+=y.x) >= MOD) x -= MOD;
        return *this;
    }
    constexpr Modint &operator-=(const Modint &y) noexcept {
        if (x < y.x) x += MOD;
        x -= y.x;
        return *this;
    }
    constexpr Modint &operator*=(const Modint &y) noexcept {
        x = (unsigned long long)x*y.x%MOD;
        return *this;
    }
    constexpr Modint &operator/=(const Modint &y) noexcept {return *this*=y.inv();}
    friend constexpr Modint operator+(const Modint &l, const Modint &r) {return Modint(l)+=r;}
    friend constexpr Modint operator-(const Modint &l, const Modint &r) {return Modint(l)-=r;}
    friend constexpr Modint operator*(const Modint &l, const Modint &r) {return Modint(l)*=r;}
    friend constexpr Modint operator/(const Modint &l, const Modint &r) {return Modint(l)/=r;}
    friend constexpr bool operator==(const Modint &l, const Modint &r) {return l.x==r.x;}
    friend constexpr bool operator!=(const Modint &l, const Modint &r) {return l.x!=r.x;}
    friend constexpr istream &operator>>(istream &is, Modint &y) {
        long long z;
        y = (is>>z, z);
        return is;
    }
    friend constexpr ostream &operator<<(ostream &os, const Modint &y) {return os<<y.x;}
};

using mint = Modint<1000000007>;

int N;
string S;
int nxt[2<<17][26];
mint dp[2<<17];

int main() {
    cin >> S;
    N = S.size();
    int last[26];
    fill(last, last+26, N+100);
    for (int i=N; i>=1; i--) {
        copy(last, last+26, nxt[i]);
        last[S[i-1]-'a'] = i;
    }
    copy(last, last+26, nxt[0]);
    dp[0] = 1;
    for (int i=0; i<N; i++) {
        for (int j=0; j<26; j++) {
            if (i && nxt[i][j]==i+1) {
                dp[nxt[nxt[i][j]][j]] += dp[i];
            } else {
                dp[nxt[i][j]] += dp[i];
            }
        }
    }
    mint ans = 0;
    for (int i=1; i<=N; i++) ans += dp[i];
    cout << ans << '\n';
}