ABC104 D - We Love ABC

解説ではDPが想定解。また他の記事にBを固定してA,C をカウントする方法もあったが、累積和を使っても比較的きれいにかける(実際には累積和しか浮かばなかった)。

解法

まず、Sの中からA, B, Cを選ぶときにたとえばAならAを選ぶ場合と?をAに変えてそれを選ぶ場合の2通りある。そのため3つの文字にどちらの方法で選ぶのか固定しChar(A)などと置く。 累積和SUM_C[i]をChar(C)がSのi番目以降で現れる個数とする。また、SUM_Bを部分列(Char(B), Char(C))がSのi番目以降で現れる個数、SUM_Aを部分列(Char(A), Char(B), Char(C))がSのi番目以降で現れる個数としておく。 すると、Char(-)を固定した場合には SUM_A[0] * 3使われていない'?'の個数 が答えになる。 あとはChar(-)を変えた8バターンを足し合わせればよい。

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);

    string S;
    cin >> S;


    ll N = S.size();
    vll res;
    rep(useQ, 0, 8) {
        vll Q(S.size() + 1);
        vll C(S.size() + 1);
        vll B(S.size() + 1);
        vll A(S.size() + 1);
        rrep(i, 0, N) {
            Q[i] = Q[i + 1] + (S[i] == '?' ? 1 : 0);
        }
        rrep(i, 0, N) {
            if (at_bit(useQ, 0)) {
                C[i] = (C[i + 1] + (S[i] == '?' ? 1 : 0)) % MOD;

            }
            else {
                C[i] = (C[i + 1] + (S[i] == 'C' ? 1 : 0)) % MOD;

            }

        }
        rrep(i, 0, N) {
            if (at_bit(useQ, 1)) {
                B[i] = (B[i + 1] +(S[i] == '?' ? C[i + 1] : 0)) % MOD;

            }
            else {
                B[i] = (B[i + 1] + (S[i] == 'B' ? C[i + 1] : 0)) % MOD;

            }

        }
        rrep(i, 0, N) {
            if (at_bit(useQ, 2)) {
                A[i] = (A[i + 1] +( S[i] == '?' ? B[i + 1] : 0)) % MOD;


            }
            else {
                A[i] = (A[i + 1] + (S[i] == 'A' ? B[i + 1] : 0)) % MOD;


            }
        }
        ll cntQ = Q[0] - (at_bit(useQ, 0) + at_bit(useQ, 1) + at_bit(useQ, 2));

        if (cntQ >= 0) {
            res.push_back((A[0] * POW_3(3LL, cntQ)) % MOD);

        }
    }

    ll out = 0;
    for (ll i : res)
        out = (out + i) % MOD;

    cout << out % MOD << endl;

    return 0;
}