Problem:
H: Revenge of UMG
問題
'U', 'M', 'G' の三種類の文字からなる文字列
T
に対し、
1, 2, ..., |T|
文字目をそれぞれ
T_1, T_2, ..., T_{|T|}
と表すことにしたとき、以下の条件を満たす
(i, j, k)
の組の個数を、文字列
T
の “UMG 数”と呼ぶことにします:
1 \leq i < j < k \leq |T|
j - i = k - j
T_i
= 'U',
T_j
= 'M',
T_k
= 'G'
さて、'U', 'M', 'G', '?' の四種類の文字からなる文字列
S
が与えられます。
S
の '?' をそれぞれ 'U', 'M', 'G' のいずれかに置き換えてできる文字列は、'?' の個数を
N
として
3^{N}
通り考えられますが、それぞれの文字列の UMG 数について総和をとったものを
998244353
で割ったあまりを求めてください。
入力形式
S
制約
3 \leq |S| \leq 2 \times 10^{5}
S
は 'U', 'M', 'G', '?' の四種類の文字からなる文字列である。
出力形式
答えを表す整数を一行に出力してください。
998244353
で割ったあまりを出力することに注意してください。
入力例 1
?MG?
出力例 1
3
最初の '?' が 'U' でない場合には UMG 数は
0
になります。最初の '?' を 'U' としたとき、
UMGU
の UMG 数は
1
UMGM
の UMG 数は
1
UMGG
の UMG 数は
1
となり、合計値は
3
になります。
入力例 2
UUMMGGGUMG
出力例 2
4
入力例 3
?????G????U???M??????G?????M????G???U??????M???G??
出力例 3
648330088
998244353
で割ったあまりを答えてください。

Submitted solutions:

code_snippet: #line 1 "library-cpp/other/template.hpp"
// clang-format off
#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <cmath>
#include <complex>
#include <deque>
#include <forward_list>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
using i128 = __int128_t;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<long long, long long>;
template <class T> using maxheap = priority_queue<T>;
template <class T> using minheap = priority_queue<T, vector<T>, greater<T>>;
template <class T> using vec = vector<T>;
template <class T> using vvec = vector<vector<T>>;
#define OVERLOAD_REP(_1, _2, _3, name, ...) name
#define REP0(n) for (auto minato = decay_t<decltype(n)>{}; minato < (n); ++minato)
#define REP1(i, n) for (auto i = decay_t<decltype(n)>{}; (i) < (n); (i)++)
#define REP2(i, l, r) for (auto i = (l); (i) < (r); (i)++)
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP2, REP1, REP0)(__VA_ARGS__)
#define OVERLOAD_RREP(_1, _2, _3, name, ...) name
#define RREP1(i, n) for (auto i = (n) - 1; (i) >= decay_t<decltype(n)>{}; (i)--)
#define RREP2(i, l, r) for (auto i = (r) - 1; (i) >= (l); (i)--)
#define rrep(...) OVERLOAD_RREP(__VA_ARGS__, RREP2, RREP1)(__VA_ARGS__)
#define all(x) begin(x), end(x)
template <class Container> int SZ(const Container& v) { return int(v.size()); }
template <class T> void UNIQUE(vector<T>& v) { v.erase(unique(v.begin(), v.end()), v.end()); }
template <class T> T MAX(const vector<T>& v) { return *max_element(v.begin(), v.end()); }
template <class T> T MIN(const vector<T>& v) { return *min_element(v.begin(), v.end()); }
template <class T> T SUM(const vector<T>& v) { return accumulate(v.begin(), v.end(), T(0)); }
template <class T> T ABS(T x) { return max(x, -x); }
template <class T1, class T2> bool chmax(T1& a, T2 b) { if (a < b) { a = b; return true; } return false; }
template <class T1, class T2> bool chmin(T1& a, T2 b) { if (a > b) { a = b; return true; } return false; }
int topbit(ull x) { return x == 0 ? -1 : 63 - __builtin_clzll(x); }
int botbit(ull x) { return x == 0 ? 64 : __builtin_ctzll(x); }
int popcount(ull x) { return __builtin_popcountll(x); }
int kthbit(ull x, int k) { return (x >> k) & 1; }
constexpr long long TEN(int x) { return x == 0 ? 1 : TEN(x - 1) * 10; }
template <typename S> void rearrange(const vector<S>& id) { (void)id; }
template <typename S, typename T> void rearrange_exec(const vector<S>& id, vector<T>& v) { vector<T> w(v.size()); for (size_t i = 0; i < id.size(); i++) { w[i] = v[id[i]]; } v.swap(w); }
template <typename S, typename Head, typename... Tail> void rearrange(const vector<S>& id, Head& a, Tail& ...tail) { rearrange_exec(id, a); rearrange(id, tail...); }
istream& operator>>(istream& is, __int128_t& x) {
    x = 0;
    string s;
    is >> s;
    int n = int(s.size()), it = 0;
    if (s[0] == '-') it++;
    for (; it < n; it++) x = (x * 10 + s[it] - '0');
    if (s[0] == '-') x = -x;
    return is;
}
ostream& operator<<(ostream& os, __int128_t x) {
    if (x == 0) return os << 0;
    if (x < 0) os << '-', x = -x;
    deque<int> deq;
    while (x) deq.emplace_front(x % 10), x /= 10;
    for (int e : deq) os << e;
    return os;
}
template <class T> vector<T> &operator++(vector<T>& v) { for (auto& e : v) { e++; } return v;} 
template <class T> vector<T> operator++(vector<T>& v, int) { auto res = v; for (auto& e : v) { e++; } return res; }
template <class T> vector<T> &operator--(vector<T>& v) { for (auto& e : v) { e--; } return v; }
template <class T> vector<T> operator--(vector<T>& v, int) { auto res = v; for (auto& e : v) { e--; } return res; }
template <class T1, class T2> pair<T1, T2> operator-(const pair<T1, T2>& x) { return pair<T1, T2>(-x.first, -x.second); }
template <class T1, class T2> pair<T1, T2> operator-(const pair<T1, T2>& x, const pair<T1, T2>& y) { return pair<T1, T2>(x.first - y.first, x.second - y.second); }
template <class T1, class T2> pair<T1, T2> operator+(const pair<T1, T2>& x, const pair<T1, T2>& y) { return pair<T1, T2>(x.first + y.first, x.second + y.second); }
template <class T1, class T2> pair<T1, T2> operator+=(pair<T1, T2>& l, const pair<T1, T2>& r) { return l = l + r; }
template <class T1, class T2> pair<T1, T2> operator-=(pair<T1, T2>& l, const pair<T1, T2>& r) { return l = l - r; }
constexpr char ln = '\n';
const string YESNO[2] = {"NO", "YES"};
const string YesNo[2] = {"No", "Yes"};
void YES(bool t = true) { cout << YESNO[t] << "\n"; }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = true) { cout << YesNo[t] << "\n"; }
void No(bool t = 1) { Yes(!t); }
template <class T> void drop(T x) { cout << x << "\n"; exit(0); }
#define INT(...)     \
    int __VA_ARGS__; \
    IN(__VA_ARGS__)
#define LL(...)     \
    ll __VA_ARGS__; \
    IN(__VA_ARGS__)
#define STR(...)        \
    string __VA_ARGS__; \
    IN(__VA_ARGS__)
#define CHR(...)      \
    char __VA_ARGS__; \
    IN(__VA_ARGS__)
#define LDB(...)             \
    long double __VA_ARGS__; \
    IN(__VA_ARGS__)
#define VEC(type, name, size) \
    vector<type> name(size);  \
    IN(name)
#define VEC2(type, name1, name2, size)     \
    vector<type> name1(size), name2(size); \
    for (int i = 0; i < size; i++) IN(name1[i], name2[i])
#define VEC3(type, name1, name2, name3, size)           \
    vector<type> name1(size), name2(size), name3(size); \
    for (int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i])
#define VEC4(type, name1, name2, name3, name4, size)                 \
    vector<type> name1(size), name2(size), name3(size), name4(size); \
    for (int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i], name4[i]);
#define VV(type, name, N, M)                       \
    vector<vector<type>> name(N, vector<type>(M)); \
    IN(name)
template <class T> void scan(T& a) { cin >> a; }
template <class T> void scan(vector<T>& a) { for (auto& i : a) scan(i); }
void IN() {}
template <class Head, class... Tail> void IN(Head& head, Tail&... tail) { scan(head); IN(tail...); }
void print() { cout << "\n"; }
template <class T> void print(const vector<T>& v) { for (auto it = v.begin(); it != v.end(); ++it) { if (it != v.begin()) { cout << " "; } cout << *it; } print(); }
template <class T, class... Args> void print(const T& x, const Args& ... args) { cout << x; if (sizeof...(Args)) cout << " "; print(args...); }
#ifdef MINATO_LOCAL
template <class T1, class T2> ostream& operator<<(ostream& os, pair<T1, T2> p) { return os << "(" << p.first << ", " << p.second << ")"; }
template <size_t N, class TUPLE> void debug_tuple(ostream& os, TUPLE _) { (void)os; (void)_; }
template <size_t N, class TUPLE, class T, class ...Args> void debug_tuple(ostream &os, TUPLE t) { os << (N == 0 ? "" : ", ") << get<N>(t); debug_tuple<N + 1, TUPLE, Args...>(os, t); }
template <class ...Args> ostream& operator<<(ostream& os, tuple<Args...> t) { os << "("; debug_tuple<0, tuple<Args...>, Args...>(os, t); return os << ")"; }
string debug_delim(int& i) { return i++ == 0 ? "" : ", "; }
#define debug_embrace(x) { int i = 0; os << "{";  { x } return os << "}"; }
template <class T> ostream& operator<<(ostream& os, vector<T> v) { debug_embrace( for (T e : v) { os << debug_delim(i) << e; } ) }
template <class T, size_t N> ostream& operator<<(ostream& os, array<T, N> a) { debug_embrace( for (T e : a) { os << debug_delim(i) << e; } ) }
template <class T, size_t N> enable_if_t<!is_same_v<char, remove_cv_t<T>>, ostream>& operator<<(ostream& os, T(&a)[N]) { debug_embrace( for (T e : a) { os << debug_delim(i) << e; } ) }
template <class Key> ostream& operator<<(ostream& os, set<Key> s) { debug_embrace( for (Key e : s) { os << debug_delim(i) << e; }) }
template <class Key, class T> ostream& operator<<(ostream& os, map<Key, T> mp) { debug_embrace( for (auto e : mp) { os << debug_delim(i) << e; }) }
template <class Key> ostream& operator<<(ostream& os, multiset<Key> s) { debug_embrace( for (Key e : s) { os << debug_delim(i) << e; }) }
template <class T> ostream& operator<<(ostream& os, queue<T> q) { debug_embrace( for (; !q.empty(); q.pop()) { os << debug_delim(i) << q.front(); } ) }
template <class T> ostream& operator<<(ostream& os, deque<T> q) { debug_embrace( for (T e : q) { os << debug_delim(i) << e; } ) }
template <class T> ostream& operator<<(ostream& os, priority_queue<T> q) { debug_embrace( for (; !q.empty(); q.pop()) { os << debug_delim(i) << q.top(); } ) }
template <class T> ostream& operator<<(ostream& os, priority_queue<T, vector<T>, greater<T>> q) { debug_embrace( for (; !q.empty(); q.pop()) { os << debug_delim(i) << q.top(); } ) }
void debug_out() { cerr << endl; }
template <class T, class... Args> void debug_out(const T& x, const Args& ... args) { cerr << " " << x; debug_out(args...); }
#define debug(...) cerr << __LINE__ << " : [" << #__VA_ARGS__ << "] =", debug_out(__VA_ARGS__)
#else
#define debug(...) (void(0))
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// clang-format on
#line 1 "library-cpp/mod/ModInt.hpp"

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

template <int m> struct ModInt {
  public:
    static constexpr int mod() {
        return m;
    }
    static ModInt raw(int v) {
        ModInt x;
        x._v = v;
        return x;
    }

    ModInt() : _v(0) {
    }
    // ModInt(long long v) {
    //     long long x = (long long)(v % (long long)(umod()));
    //     if (x < 0) x += umod();
    //     _v = (unsigned int)(x);
    // }
    template <class T, internal::is_signed_int_t<T>* = nullptr> ModInt(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr> ModInt(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const {
        return _v;
    }

    ModInt& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    ModInt& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    ModInt operator++(int) {
        ModInt result = *this;
        ++*this;
        return result;
    }
    ModInt operator--(int) {
        ModInt result = *this;
        --*this;
        return result;
    }

    ModInt& operator+=(const ModInt& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    ModInt& operator-=(const ModInt& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    ModInt& operator*=(const ModInt& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    ModInt& operator^=(long long n) {
        ModInt x = *this;
        *this = 1;
        if (n < 0) x = x.inv(), n = -n;
        while (n) {
            if (n & 1) *this *= x;
            x *= x;
            n >>= 1;
        }
        return *this;
    }
    ModInt& operator/=(const ModInt& rhs) {
        return *this = *this * rhs.inv();
    }

    ModInt operator+() const {
        return *this;
    }
    ModInt operator-() const {
        return ModInt() - *this;
    }
    explicit operator bool() const {
        return _v != 0;
    }

    ModInt pow(long long n) const {
        ModInt r = *this;
        r ^= n;
        return r;
    }
    ModInt inv() const {
        int a = _v, b = umod(), y = 1, z = 0, t;
        for (;;) {
            t = a / b;
            a -= t * b;
            if (a == 0) {
                assert(b == 1 || b == -1);
                return ModInt(b * z);
            }
            y -= t * z;
            t = b / a;
            b -= t * a;
            if (b == 0) {
                assert(a == 1 || a == -1);
                return ModInt(a * y);
            }
            z -= t * y;
        }
    }

    friend ModInt operator+(const ModInt& lhs, const ModInt& rhs) {
        return ModInt(lhs) += rhs;
    }
    friend ModInt operator-(const ModInt& lhs, const ModInt& rhs) {
        return ModInt(lhs) -= rhs;
    }
    friend ModInt operator*(const ModInt& lhs, const ModInt& rhs) {
        return ModInt(lhs) *= rhs;
    }
    friend ModInt operator/(const ModInt& lhs, const ModInt& rhs) {
        return ModInt(lhs) /= rhs;
    }
    friend ModInt operator^(const ModInt& lhs, long long rhs) {
        return ModInt(lhs) ^= rhs;
    }
    friend bool operator==(const ModInt& lhs, const ModInt& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const ModInt& lhs, const ModInt& rhs) {
        return lhs._v != rhs._v;
    }
    friend ModInt operator+(long long lhs, const ModInt& rhs) {
        return (ModInt(lhs) += rhs);
    }
    friend ModInt operator-(long long lhs, const ModInt& rhs) {
        return (ModInt(lhs) -= rhs);
    }
    friend ModInt operator*(long long lhs, const ModInt& rhs) {
        return (ModInt(lhs) *= rhs);
    }
    friend ostream& operator<<(ostream& os, const ModInt& M) {
        return os << M._v;
    }
    friend istream& operator>>(istream& is, ModInt& M) {
        long long x;
        is >> x;
        M = x;
        return is;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() {
        return m;
    }
};
#line 2 "library-cpp/mod/ModCombination.hpp"

template <class M> struct ModCombination {
  public:
    ModCombination() {
    }
    ModCombination(int n) : n_(n), fac_(n + 1), facinv_(n + 1) {
        assert(1 <= n);
        fac_[0] = 1;
        for (int i = 1; i <= n; i++) fac_[i] = fac_[i - 1] * i;
        facinv_[n] = M(1) / fac_[n];
        for (int i = n; i >= 1; i--) facinv_[i - 1] = facinv_[i] * i;
    }

    M fac(int k) const {
        assert(0 <= k and k <= n_);
        return fac_[k];
    }
    M facinv(int k) const {
        assert(0 <= k and k <= n_);
        return facinv_[k];
    }
    M inv(int k) const {
        assert(1 <= k and k <= n_);
        return facinv_[k] * fac_[k - 1];
    }

    M P(int n, int k) const {
        if (k < 0 or k > n) return M(0);
        assert(n <= n_);
        return fac_[n] * facinv_[n - k];
    }
    M C(int n, int k) const {
        if (k < 0 or k > n) return M(0);
        assert(n <= n_);
        return fac_[n] * facinv_[n - k] * facinv_[k];
    }

    /**
     * @note H(n, k) = (n 個 のボールを k 個の箱に分ける方法の数)
     * @note H(n, k) = C(n + k - 1, n)
     */
    M H(int n, int k) const {
        if (n == 0 and k == 0) return M(1);
        return C(n + k - 1, n);
    }
    M catalan(int n) const {
        if (n == 0) return M(1);
        return C(2 * n, n) - C(2 * n, n - 1);
    }

  private:
    int n_;
    vector<M> fac_, facinv_;
};
#line 4 "A.cpp"
using mint = ModInt<998244353>;
// using mint = ModInt<1000000007>;
#line 2 "library-cpp/mod/convolution998244353.hpp"

#line 5 "library-cpp/mod/convolution998244353.hpp"

namespace internal {

// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

template <class mint> struct fft_info {
    static constexpr int rank2 = 23;
    static constexpr int g = 3;
    std::array<mint, rank2 + 1> root;   // root[i]^(2^i) == 1
    std::array<mint, rank2 + 1> iroot;  // root[i] * iroot[i] == 1

    std::array<mint, rank2 - 1> rate2;
    std::array<mint, rank2 - 1> irate2;

    std::array<mint, rank2 - 2> rate3;
    std::array<mint, rank2 - 2> irate3;

    fft_info() {
        root[rank2] = mint(g).pow((mint::mod() - 1) >> rank2);
        iroot[rank2] = root[rank2].inv();
        for (int i = rank2 - 1; i >= 0; i--) {
            root[i] = root[i + 1] * root[i + 1];
            iroot[i] = iroot[i + 1] * iroot[i + 1];
        }

        {
            mint prod = 1, iprod = 1;
            for (int i = 0; i <= rank2 - 2; i++) {
                rate2[i] = root[i + 2] * prod;
                irate2[i] = iroot[i + 2] * iprod;
                prod *= iroot[i + 2];
                iprod *= root[i + 2];
            }
        }
        {
            mint prod = 1, iprod = 1;
            for (int i = 0; i <= rank2 - 3; i++) {
                rate3[i] = root[i + 3] * prod;
                irate3[i] = iroot[i + 3] * iprod;
                prod *= iroot[i + 3];
                iprod *= root[i + 3];
            }
        }
    }
};

template <class mint> void butterfly(std::vector<mint>& a) {
    int n = int(a.size());
    int h = internal::ceil_pow2(n);

    static const fft_info<mint> info;

    int len = 0;  // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed
    while (len < h) {
        if (h - len == 1) {
            int p = 1 << (h - len - 1);
            mint rot = 1;
            for (int s = 0; s < (1 << len); s++) {
                int offset = s << (h - len);
                for (int i = 0; i < p; i++) {
                    auto l = a[i + offset];
                    auto r = a[i + offset + p] * rot;
                    a[i + offset] = l + r;
                    a[i + offset + p] = l - r;
                }
                if (s + 1 != (1 << len))
                    rot *= info.rate2[bsf(~(unsigned int)(s))];
            }
            len++;
        } else {
            // 4-base
            int p = 1 << (h - len - 2);
            mint rot = 1, imag = info.root[2];
            for (int s = 0; s < (1 << len); s++) {
                mint rot2 = rot * rot;
                mint rot3 = rot2 * rot;
                int offset = s << (h - len);
                for (int i = 0; i < p; i++) {
                    auto mod2 = 1ULL * mint::mod() * mint::mod();
                    auto a0 = 1ULL * a[i + offset].val();
                    auto a1 = 1ULL * a[i + offset + p].val() * rot.val();
                    auto a2 = 1ULL * a[i + offset + 2 * p].val() * rot2.val();
                    auto a3 = 1ULL * a[i + offset + 3 * p].val() * rot3.val();
                    auto a1na3imag =
                        1ULL * mint(a1 + mod2 - a3).val() * imag.val();
                    auto na2 = mod2 - a2;
                    a[i + offset] = a0 + a2 + a1 + a3;
                    a[i + offset + 1 * p] = a0 + a2 + (2 * mod2 - (a1 + a3));
                    a[i + offset + 2 * p] = a0 + na2 + a1na3imag;
                    a[i + offset + 3 * p] = a0 + na2 + (mod2 - a1na3imag);
                }
                if (s + 1 != (1 << len))
                    rot *= info.rate3[bsf(~(unsigned int)(s))];
            }
            len += 2;
        }
    }
}

template <class mint> void butterfly_inv(std::vector<mint>& a) {
    int n = int(a.size());
    int h = internal::ceil_pow2(n);

    static const fft_info<mint> info;

    int len = h;  // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed
    while (len) {
        if (len == 1) {
            int p = 1 << (h - len);
            mint irot = 1;
            for (int s = 0; s < (1 << (len - 1)); s++) {
                int offset = s << (h - len + 1);
                for (int i = 0; i < p; i++) {
                    auto l = a[i + offset];
                    auto r = a[i + offset + p];
                    a[i + offset] = l + r;
                    a[i + offset + p] =
                        (unsigned long long)(mint::mod() + l.val() - r.val()) *
                        irot.val();
                    ;
                }
                if (s + 1 != (1 << (len - 1)))
                    irot *= info.irate2[bsf(~(unsigned int)(s))];
            }
            len--;
        } else {
            // 4-base
            int p = 1 << (h - len);
            mint irot = 1, iimag = info.iroot[2];
            for (int s = 0; s < (1 << (len - 2)); s++) {
                mint irot2 = irot * irot;
                mint irot3 = irot2 * irot;
                int offset = s << (h - len + 2);
                for (int i = 0; i < p; i++) {
                    auto a0 = 1ULL * a[i + offset + 0 * p].val();
                    auto a1 = 1ULL * a[i + offset + 1 * p].val();
                    auto a2 = 1ULL * a[i + offset + 2 * p].val();
                    auto a3 = 1ULL * a[i + offset + 3 * p].val();

                    auto a2na3iimag =
                        1ULL *
                        mint((mint::mod() + a2 - a3) * iimag.val()).val();

                    a[i + offset] = a0 + a1 + a2 + a3;
                    a[i + offset + 1 * p] =
                        (a0 + (mint::mod() - a1) + a2na3iimag) * irot.val();
                    a[i + offset + 2 * p] =
                        (a0 + a1 + (mint::mod() - a2) + (mint::mod() - a3)) *
                        irot2.val();
                    a[i + offset + 3 * p] =
                        (a0 + (mint::mod() - a1) + (mint::mod() - a2na3iimag)) *
                        irot3.val();
                }
                if (s + 1 != (1 << (len - 2)))
                    irot *= info.irate3[bsf(~(unsigned int)(s))];
            }
            len -= 2;
        }
    }
}

template <class mint>
std::vector<mint> convolution_fft(std::vector<mint> a, std::vector<mint> b) {
    int n = int(a.size()), m = int(b.size());
    int z = 1 << internal::ceil_pow2(n + m - 1);
    a.resize(z);
    internal::butterfly(a);
    b.resize(z);
    internal::butterfly(b);
    for (int i = 0; i < z; i++) {
        a[i] *= b[i];
    }
    internal::butterfly_inv(a);
    a.resize(n + m - 1);
    mint iz = mint(z).inv();
    for (int i = 0; i < n + m - 1; i++) a[i] *= iz;
    return a;
}
}  // namespace internal

template <class mint>
std::vector<mint> convolution_naive(const std::vector<mint>& a,
                                    const std::vector<mint>& b) {
    int n = int(a.size()), m = int(b.size());
    std::vector<mint> ans(n + m - 1);
    if (n < m) {
        for (int j = 0; j < m; j++) {
            for (int i = 0; i < n; i++) {
                ans[i + j] += a[i] * b[j];
            }
        }
    } else {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                ans[i + j] += a[i] * b[j];
            }
        }
    }
    return ans;
}

template <class mint>
std::vector<mint> convolution(std::vector<mint>&& a, std::vector<mint>&& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};
    if (std::min(n, m) <= 60) return convolution_naive(a, b);
    return internal::convolution_fft(a, b);
}

template <class mint>
std::vector<mint> convolution(const std::vector<mint>& a,
                              const std::vector<mint>& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};
    if (std::min(n, m) <= 60) return convolution_naive(a, b);
    return internal::convolution_fft(a, b);
}
#line 7 "A.cpp"

void solve() {
    STR(S);
    int N = S.size();

    vec<mint> dp(N * 2);

    mint three = mint(3).inv();
    auto rec = [&](auto self, int l, int r) -> void {
        if (r - l == 1) return;
        int m = (l + r) / 2;
        vec<mint> U(m - l), G(r - m);
        rep(i, l, m) {
            if (S[i] == 'U')
                U[i - l] = 1;
            else if (S[i] == '?')
                U[i - l] = three;
        }
        rep(i, m, r) {
            if (S[i] == 'G')
                G[i - m] = 1;
            else if (S[i] == '?')
                G[i - m] = three;
        }
        auto M = convolution(U, G);
        rep(i, r - l - 1) {
            dp[i + l + m] += M[i];
        }
        self(self, l, m);
        self(self, m, r);
    };
    rec(rec, 0, N);
    mint ans = 0;
    rep(i, 1, N - 1) {
        if (S[i] == 'M') {
            ans += dp[i * 2];
        } else if (S[i] == '?') {
            ans += dp[i * 2] * three;
        }
    }
    int Q = count(all(S), '?');
    ans *= mint(3).pow(Q);
    print(ans);
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(20);
    cerr << fixed << setprecision(7);

    int T = 1;
    // cin >> T;
    for (int test_case = 1; test_case <= T; test_case++) {
        // debug(test_case);
        solve();
    }
}
accuracy: 1
time_ms: 120
memory_kb: 8984
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize("Ofast")

#define rep(i,n) for(ll i=0;i<n;i++)
#define repl(i,l,r) for(ll i=(l);i<(r);i++)
#define per(i,n) for(ll i=(n)-1;i>=0;i--)
#define perl(i,r,l) for(ll i=r-1;i>=l;i--)
#define fi first
#define se second
#define pb push_back
#define ins insert
#define pqueue(x) priority_queue<x,vector<x>,greater<x>>
#define all(x) (x).begin(),(x).end()
#define CST(x) cout<<fixed<<setprecision(x)
#define vtpl(x,y,z) vector<tuple<x,y,z>>
#define rev(x) reverse(x);
using ll=long long;
using vl=vector<ll>;
using vvl=vector<vector<ll>>;
using pl=pair<ll,ll>;
using vpl=vector<pl>;
using vvpl=vector<vpl>;
const ll MOD=1000000007;
const ll MOD9=998244353;
const int inf=1e9+10;
const ll INF=4e18;
const ll dy[9]={1,0,-1,0,1,1,-1,-1,0};
const ll dx[9]={0,1,0,-1,1,-1,1,-1,0};
template<class T> inline bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template<class T> inline bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

const int mod = MOD9;
const int max_n = 200005;
struct mint {
  ll x; // typedef long long ll;
  mint(ll x=0):x((x%mod+mod)%mod){}
  mint operator-() const { return mint(-x);}
  mint& operator+=(const mint a) {
    if ((x += a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator-=(const mint a) {
    if ((x += mod-a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this;}
  mint operator+(const mint a) const { return mint(*this) += a;}
  mint operator-(const mint a) const { return mint(*this) -= a;}
  mint operator*(const mint a) const { return mint(*this) *= a;}
  mint pow(ll t) const {
    if (!t) return 1;
    mint a = pow(t>>1);
    a *= a;
    if (t&1) a *= *this;
    return a;
  }
  bool operator==(const mint &p) const { return x == p.x; }
  bool operator!=(const mint &p) const { return x != p.x; }
  // for prime mod
  mint inv() const { return pow(mod-2);}
  mint& operator/=(const mint a) { return *this *= a.inv();}
  mint operator/(const mint a) const { return mint(*this) /= a;}
};
istream& operator>>(istream& is, mint& a) { return is >> a.x;}
ostream& operator<<(ostream& os, const mint& a) { return os << a.x;}
using vm=vector<mint>;
using vvm=vector<vm>;
struct combination {
  vector<mint> fact, ifact;
  combination(int n):fact(n+1),ifact(n+1) {
    assert(n < mod);
    fact[0] = 1;
    for (int i = 1; i <= n; ++i) fact[i] = fact[i-1]*i;
    ifact[n] = fact[n].inv();
    for (int i = n; i >= 1; --i) ifact[i-1] = ifact[i]*i;
  }
  mint operator()(int n, int k) {
    if (k < 0 || k > n) return 0;
    return fact[n]*ifact[k]*ifact[n-k];
  }
}comb(max_n);



unordered_map<ll,mint> memo;
mint PR(ll t){
    if(memo.count(t))return memo[t];
    else return memo[t]=mint(3).pow(t);
}
unordered_map<ll,mint> memo2;
mint INV(mint p){
    if(memo2.count(p.x))return memo2[p.x];
    else return memo2[p.x]=p.pow(MOD9-2);
}

namespace NTT {
    //MOD9のNTT auto c=NTT::mul(a,b)で受け取り。
	vector<mint> tmp;
	size_t sz = 1;
    mint PrimitiveRoot=3;
	struct NTTPart {
		static std::vector<mint> ntt(std::vector<mint> a, bool inv = false) {
			size_t mask = sz - 1;
			size_t p = 0;
			for (size_t i = sz >> 1; i >= 1; i >>= 1) {
				auto& cur = (p & 1) ? tmp : a;
				auto& nex = (p & 1) ? a : tmp;
				mint e = PR((MOD9 - 1) / sz * i);
				if (inv) e = INV(e);
				mint w = 1;
				for (size_t j = 0; j < sz; j += i) {
					for (size_t k = 0; k < i; ++k) {
						nex[j + k] = cur[((j << 1) & mask) + k] + cur[(((j << 1) + i) & mask) + k] * w;
					}
					w *= e;
				}
				++p;
			}
			if (p & 1) std::swap(a, tmp);
			if (inv) {
				mint invSz = INV(mint(sz));
				for (size_t i = 0; i < sz; ++i) a[i] *= invSz;
			}
			return a;
		}
		static std::vector<mint> mul(std::vector<mint> a, std::vector<mint> b) {
			a = ntt(a);
			b = ntt(b);
			for (size_t i = 0; i < sz; ++i) a[i] = a[i] * b[i];
			a = ntt(a, true);
			return a;
		}
	};
	std::vector<mint> mul(std::vector<mint> a, std::vector<mint> b) {
		size_t m = a.size() + b.size() - 1;
		sz = 1;
		while (m > sz) sz <<= 1;
		tmp.resize(sz);
		a.resize(sz, 0);
		b.resize(sz, 0);
		vector<mint> c=NTTPart::mul(a, b);
		c.resize(m);
		return c;
	}
};

//C[k]=A[i]*B[j],i<j なる畳み込み,O(Nlog^2N)
vm half_convolution(vm a,vm b){
    ll n=a.size(),m=b.size();
    if(n+m<16){
        vm c(n+m-1);
        rep(i,n)repl(j,i+1,m){
            c[i+j]+=a[i]*b[j];
        }
        return c;
    }
    ll l=max(n,m);if(l&1)l++;
    m=l/2;
    vm c(m);rep(i,m)if(a.size()>i+m)c[i]=a[i+m];
    vm d(m);rep(i,m)if(b.size()>i+m)d[i]=b[i+m];
    a.resize(m,0);b.resize(m,0);
    vm ans(l*2);
    vm f=half_convolution(a,b);
    rep(i,f.size())ans[i]+=f[i];
    f=half_convolution(c,d);
    rep(i,f.size())ans[i+l]+=f[i];
    f=NTT::mul(a,d);
    rep(i,f.size())ans[i+m]+=f[i];
    return ans;
}

int main(){
    /*vm a={1,2,3,4},b={1,2,3,4};
    auto c=half_convolution(a,b);
    rep(i,c.size())cout << c[i] <<" ";cout << endl;return 0;*/
    string s;cin >> s;ll n=s.size();
    ll K=0;rep(i,n)if(s[i]=='?')K++;
    mint inv3=mint(1)/3;
    vm a(n),b(n);
    rep(i,n){
        if(s[i]=='U')a[i]=1;
        if(s[i]=='G')b[i]=1;
        if(s[i]=='?'){
            a[i]=inv3;b[i]=inv3;
        }
    }
    //vm c(n+n-1);
    /*rep(i,n){
        rep(j,n){
            if(i>=j)continue;
            c[i+j]+=a[i]*b[j];
        }
    }*/
    auto c=half_convolution(a,b);
    mint ans=0;
    rep(i,n){
        if(s[i]=='M')ans+=c[i*2];
        if(s[i]=='?')ans+=c[i*2]*inv3;
    }
    rep(_,K)ans*=3;
    cout << ans << endl;
}
accuracy: 1
time_ms: 340
memory_kb: 32712
final_rank: 7

code_snippet: #include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
using std::cout;
using std::cin;
using std::endl;
using ll=long long;
using ld=long double;
ll ILL=1167167167167167167;
const int INF=10000000;
const ll mod=998244353;

#define rep(i,a) for (int i=0;i<a;i++)
#define all(p) p.begin(),p.end()
template<class T> using _pq = priority_queue<T, vector<T>, greater<T>>;
template<class T> ll LB(vector<T> &v,T a){return lower_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> ll UB(vector<T> &v,T a){return upper_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> bool chmin(T &a,const T &b){if(a>b){a=b;return 1;}else return 0;}
template<class T> bool chmax(T &a,const T &b){if(a<b){a=b;return 1;}else return 0;}
template<class T> void So(vector<T> &v) {sort(v.begin(),v.end());}
template<class T> void Sore(vector<T> &v) {sort(v.begin(),v.end(),[](T x,T y){return x>y;});}
void yneos(bool a){if(a) cout<<"Yes\n"; else cout<<"No\n";}
template<class T> void vec_out(vector<T> &p){for(int i=0;i<(int)(p.size());i++){if(i) cout<<" ";cout<<p[i];}cout<<"\n";}

namespace atcoder {

namespace internal {

// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

}  // namespace internal

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

}  // namespace internal

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal



namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }
    static_modint(bool v) { _v = ((unsigned int)(v) % umod()); }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }
    dynamic_modint(bool v) { _v = ((unsigned int)(v) % mod()); }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

namespace internal {

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly(std::vector<mint>& a) {
    static constexpr int g = internal::primitive_root<mint::mod()>;
    int n = int(a.size());
    int h = internal::ceil_pow2(n);

    static bool first = true;
    static mint sum_e[30];  // sum_e[i] = ies[0] * ... * ies[i - 1] * es[i]
    if (first) {
        first = false;
        mint es[30], ies[30];  // es[i]^(2^(2+i)) == 1
        int cnt2 = bsf(mint::mod() - 1);
        mint e = mint(g).pow((mint::mod() - 1) >> cnt2), ie = e.inv();
        for (int i = cnt2; i >= 2; i--) {
            // e^(2^i) == 1
            es[i - 2] = e;
            ies[i - 2] = ie;
            e *= e;
            ie *= ie;
        }
        mint now = 1;
        for (int i = 0; i <= cnt2 - 2; i++) {
            sum_e[i] = es[i] * now;
            now *= ies[i];
        }
    }
    for (int ph = 1; ph <= h; ph++) {
        int w = 1 << (ph - 1), p = 1 << (h - ph);
        mint now = 1;
        for (int s = 0; s < w; s++) {
            int offset = s << (h - ph + 1);
            for (int i = 0; i < p; i++) {
                auto l = a[i + offset];
                auto r = a[i + offset + p] * now;
                a[i + offset] = l + r;
                a[i + offset + p] = l - r;
            }
            now *= sum_e[bsf(~(unsigned int)(s))];
        }
    }
}

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly_inv(std::vector<mint>& a) {
    static constexpr int g = internal::primitive_root<mint::mod()>;
    int n = int(a.size());
    int h = internal::ceil_pow2(n);

    static bool first = true;
    static mint sum_ie[30];  // sum_ie[i] = es[0] * ... * es[i - 1] * ies[i]
    if (first) {
        first = false;
        mint es[30], ies[30];  // es[i]^(2^(2+i)) == 1
        int cnt2 = bsf(mint::mod() - 1);
        mint e = mint(g).pow((mint::mod() - 1) >> cnt2), ie = e.inv();
        for (int i = cnt2; i >= 2; i--) {
            // e^(2^i) == 1
            es[i - 2] = e;
            ies[i - 2] = ie;
            e *= e;
            ie *= ie;
        }
        mint now = 1;
        for (int i = 0; i <= cnt2 - 2; i++) {
            sum_ie[i] = ies[i] * now;
            now *= es[i];
        }
    }

    for (int ph = h; ph >= 1; ph--) {
        int w = 1 << (ph - 1), p = 1 << (h - ph);
        mint inow = 1;
        for (int s = 0; s < w; s++) {
            int offset = s << (h - ph + 1);
            for (int i = 0; i < p; i++) {
                auto l = a[i + offset];
                auto r = a[i + offset + p];
                a[i + offset] = l + r;
                a[i + offset + p] =
                    (unsigned long long)(mint::mod() + l.val() - r.val()) *
                    inow.val();
            }
            inow *= sum_ie[bsf(~(unsigned int)(s))];
        }
    }
}

}  // namespace internal

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
std::vector<mint> convolution(std::vector<mint> a, std::vector<mint> b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};
    if (std::min(n, m) <= 60) {
        if (n < m) {
            std::swap(n, m);
            std::swap(a, b);
        }
        std::vector<mint> ans(n + m - 1);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                ans[i + j] += a[i] * b[j];
            }
        }
        return ans;
    }
    int z = 1 << internal::ceil_pow2(n + m - 1);
    a.resize(z);
    internal::butterfly(a);
    b.resize(z);
    internal::butterfly(b);
    for (int i = 0; i < z; i++) {
        a[i] *= b[i];
    }
    internal::butterfly_inv(a);
    a.resize(n + m - 1);
    mint iz = mint(z).inv();
    for (int i = 0; i < n + m - 1; i++) a[i] *= iz;
    return a;
}

template <unsigned int mod = 998244353,
          class T,
          std::enable_if_t<internal::is_integral<T>::value>* = nullptr>
std::vector<T> convolution(const std::vector<T>& a, const std::vector<T>& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};

    using mint = static_modint<mod>;
    std::vector<mint> a2(n), b2(m);
    for (int i = 0; i < n; i++) {
        a2[i] = mint(a[i]);
    }
    for (int i = 0; i < m; i++) {
        b2[i] = mint(b[i]);
    }
    auto c2 = convolution(move(a2), move(b2));
    std::vector<T> c(n + m - 1);
    for (int i = 0; i < n + m - 1; i++) {
        c[i] = c2[i].val();
    }
    return c;
}

std::vector<long long> convolution_ll(const std::vector<long long>& a,
                                      const std::vector<long long>& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};

    static constexpr unsigned long long MOD1 = 754974721;  // 2^24
    static constexpr unsigned long long MOD2 = 167772161;  // 2^25
    static constexpr unsigned long long MOD3 = 469762049;  // 2^26
    static constexpr unsigned long long M2M3 = MOD2 * MOD3;
    static constexpr unsigned long long M1M3 = MOD1 * MOD3;
    static constexpr unsigned long long M1M2 = MOD1 * MOD2;
    static constexpr unsigned long long M1M2M3 = MOD1 * MOD2 * MOD3;

    static constexpr unsigned long long i1 =
        internal::inv_gcd(MOD2 * MOD3, MOD1).second;
    static constexpr unsigned long long i2 =
        internal::inv_gcd(MOD1 * MOD3, MOD2).second;
    static constexpr unsigned long long i3 =
        internal::inv_gcd(MOD1 * MOD2, MOD3).second;

    auto c1 = convolution<MOD1>(a, b);
    auto c2 = convolution<MOD2>(a, b);
    auto c3 = convolution<MOD3>(a, b);

    std::vector<long long> c(n + m - 1);
    for (int i = 0; i < n + m - 1; i++) {
        unsigned long long x = 0;
        x += (c1[i] * i1) % MOD1 * M2M3;
        x += (c2[i] * i2) % MOD2 * M1M3;
        x += (c3[i] * i3) % MOD3 * M1M2;
        // B = 2^63, -B <= x, r(real value) < B
        // (x, x - M, x - 2M, or x - 3M) = r (mod 2B)
        // r = c1[i] (mod MOD1)
        // focus on MOD1
        // r = x, x - M', x - 2M', x - 3M' (M' = M % 2^64) (mod 2B)
        // r = x,
        //     x - M' + (0 or 2B),
        //     x - 2M' + (0, 2B or 4B),
        //     x - 3M' + (0, 2B, 4B or 6B) (without mod!)
        // (r - x) = 0, (0)
        //           - M' + (0 or 2B), (1)
        //           -2M' + (0 or 2B or 4B), (2)
        //           -3M' + (0 or 2B or 4B or 6B) (3) (mod MOD1)
        // we checked that
        //   ((1) mod MOD1) mod 5 = 2
        //   ((2) mod MOD1) mod 5 = 3
        //   ((3) mod MOD1) mod 5 = 4
        long long diff =
            c1[i] - internal::safe_mod((long long)(x), (long long)(MOD1));
        if (diff < 0) diff += MOD1;
        static constexpr unsigned long long offset[5] = {
            0, 0, M1M2M3, 2 * M1M2M3, 3 * M1M2M3};
        x -= offset[diff % 5];
        c[i] = x;
    }

    return c;
}

}  // namespace atcoder
using namespace atcoder;




void solve();
// oddloop
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t=1;
	//cin>>t;
	rep(i,t) solve();
}

void solve(){
	string S;
	cin>>S;int N=S.size();
	vector<ll> dp(N*2);
	ll rev=(mod+1)/3;
	auto f=[&](auto self,int l,int r)->void{
		if(r-l<3) return;
		int med=(l+r)/2;
		vector<ll> A(med-l),B(r-med);
		for(int i=l;i<r;i++){
			if(i<med){
				if(S[i]=='?') A[i-l]=rev;
				if(S[i]=='U') A[i-l]=1;
			}else{
				if(S[i]=='?') B[i-med]=rev;
				if(S[i]=='G') B[i-med]=1;
			}
		}
		auto C=convolution<mod>(A,B);
		rep(i,(int)(C.size())){
			dp[l+med+i]=(dp[l+med+i]+C[i])%mod;
		}
		self(self,l,med);
		self(self,med,r);
	};
	f(f,0,N);
	ll ans=0;
	rep(i,N){
		if(S[i]=='?') ans=(ans+rev*dp[i*2])%mod;
		if(S[i]=='M') ans=(ans+1ll*dp[i*2])%mod;
	}
	rep(i,N){
		if(S[i]=='?') ans=(ans*3ll)%mod;
	}
	cout<<ans<<"\n";
}
accuracy: 1
time_ms: 340
memory_kb: 12916
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;

using ll = long long;
const int INF = 1e9;
const ll inf = 1LL<<55;
namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal


namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

}  // namespace internal


namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }
    static_modint(bool v) { _v = ((unsigned int)(v) % umod()); }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }
    dynamic_modint(bool v) { _v = ((unsigned int)(v) % mod()); }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

namespace internal {

// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

}  // namespace internal


namespace internal {

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly(std::vector<mint>& a) {
    static constexpr int g = internal::primitive_root<mint::mod()>;
    int n = int(a.size());
    int h = internal::ceil_pow2(n);

    static bool first = true;
    static mint sum_e[30];  // sum_e[i] = ies[0] * ... * ies[i - 1] * es[i]
    if (first) {
        first = false;
        mint es[30], ies[30];  // es[i]^(2^(2+i)) == 1
        int cnt2 = bsf(mint::mod() - 1);
        mint e = mint(g).pow((mint::mod() - 1) >> cnt2), ie = e.inv();
        for (int i = cnt2; i >= 2; i--) {
            // e^(2^i) == 1
            es[i - 2] = e;
            ies[i - 2] = ie;
            e *= e;
            ie *= ie;
        }
        mint now = 1;
        for (int i = 0; i <= cnt2 - 2; i++) {
            sum_e[i] = es[i] * now;
            now *= ies[i];
        }
    }
    for (int ph = 1; ph <= h; ph++) {
        int w = 1 << (ph - 1), p = 1 << (h - ph);
        mint now = 1;
        for (int s = 0; s < w; s++) {
            int offset = s << (h - ph + 1);
            for (int i = 0; i < p; i++) {
                auto l = a[i + offset];
                auto r = a[i + offset + p] * now;
                a[i + offset] = l + r;
                a[i + offset + p] = l - r;
            }
            now *= sum_e[bsf(~(unsigned int)(s))];
        }
    }
}

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly_inv(std::vector<mint>& a) {
    static constexpr int g = internal::primitive_root<mint::mod()>;
    int n = int(a.size());
    int h = internal::ceil_pow2(n);

    static bool first = true;
    static mint sum_ie[30];  // sum_ie[i] = es[0] * ... * es[i - 1] * ies[i]
    if (first) {
        first = false;
        mint es[30], ies[30];  // es[i]^(2^(2+i)) == 1
        int cnt2 = bsf(mint::mod() - 1);
        mint e = mint(g).pow((mint::mod() - 1) >> cnt2), ie = e.inv();
        for (int i = cnt2; i >= 2; i--) {
            // e^(2^i) == 1
            es[i - 2] = e;
            ies[i - 2] = ie;
            e *= e;
            ie *= ie;
        }
        mint now = 1;
        for (int i = 0; i <= cnt2 - 2; i++) {
            sum_ie[i] = ies[i] * now;
            now *= es[i];
        }
    }

    for (int ph = h; ph >= 1; ph--) {
        int w = 1 << (ph - 1), p = 1 << (h - ph);
        mint inow = 1;
        for (int s = 0; s < w; s++) {
            int offset = s << (h - ph + 1);
            for (int i = 0; i < p; i++) {
                auto l = a[i + offset];
                auto r = a[i + offset + p];
                a[i + offset] = l + r;
                a[i + offset + p] =
                    (unsigned long long)(mint::mod() + l.val() - r.val()) *
                    inow.val();
            }
            inow *= sum_ie[bsf(~(unsigned int)(s))];
        }
    }
}

}  // namespace internal

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
std::vector<mint> convolution(std::vector<mint> a, std::vector<mint> b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};
    if (std::min(n, m) <= 60) {
        if (n < m) {
            std::swap(n, m);
            std::swap(a, b);
        }
        std::vector<mint> ans(n + m - 1);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                ans[i + j] += a[i] * b[j];
            }
        }
        return ans;
    }
    int z = 1 << internal::ceil_pow2(n + m - 1);
    a.resize(z);
    internal::butterfly(a);
    b.resize(z);
    internal::butterfly(b);
    for (int i = 0; i < z; i++) {
        a[i] *= b[i];
    }
    internal::butterfly_inv(a);
    a.resize(n + m - 1);
    mint iz = mint(z).inv();
    for (int i = 0; i < n + m - 1; i++) a[i] *= iz;
    return a;
}

template <unsigned int mod = 998244353,
          class T,
          std::enable_if_t<internal::is_integral<T>::value>* = nullptr>
std::vector<T> convolution(const std::vector<T>& a, const std::vector<T>& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};

    using mint = static_modint<mod>;
    std::vector<mint> a2(n), b2(m);
    for (int i = 0; i < n; i++) {
        a2[i] = mint(a[i]);
    }
    for (int i = 0; i < m; i++) {
        b2[i] = mint(b[i]);
    }
    auto c2 = convolution(move(a2), move(b2));
    std::vector<T> c(n + m - 1);
    for (int i = 0; i < n + m - 1; i++) {
        c[i] = c2[i].val();
    }
    return c;
}

std::vector<long long> convolution_ll(const std::vector<long long>& a,
                                      const std::vector<long long>& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};

    static constexpr unsigned long long MOD1 = 754974721;  // 2^24
    static constexpr unsigned long long MOD2 = 167772161;  // 2^25
    static constexpr unsigned long long MOD3 = 469762049;  // 2^26
    static constexpr unsigned long long M2M3 = MOD2 * MOD3;
    static constexpr unsigned long long M1M3 = MOD1 * MOD3;
    static constexpr unsigned long long M1M2 = MOD1 * MOD2;
    static constexpr unsigned long long M1M2M3 = MOD1 * MOD2 * MOD3;

    static constexpr unsigned long long i1 =
        internal::inv_gcd(MOD2 * MOD3, MOD1).second;
    static constexpr unsigned long long i2 =
        internal::inv_gcd(MOD1 * MOD3, MOD2).second;
    static constexpr unsigned long long i3 =
        internal::inv_gcd(MOD1 * MOD2, MOD3).second;

    auto c1 = convolution<MOD1>(a, b);
    auto c2 = convolution<MOD2>(a, b);
    auto c3 = convolution<MOD3>(a, b);

    std::vector<long long> c(n + m - 1);
    for (int i = 0; i < n + m - 1; i++) {
        unsigned long long x = 0;
        x += (c1[i] * i1) % MOD1 * M2M3;
        x += (c2[i] * i2) % MOD2 * M1M3;
        x += (c3[i] * i3) % MOD3 * M1M2;
        long long diff =
            c1[i] - internal::safe_mod((long long)(x), (long long)(MOD1));
        if (diff < 0) diff += MOD1;
        static constexpr unsigned long long offset[5] = {
            0, 0, M1M2M3, 2 * M1M2M3, 3 * M1M2M3};
        x -= offset[diff % 5];
        c[i] = x;
    }

    return c;
}

using mint = modint998244353;

mint online_convolution(const string &S, int left, int right) {
  if (right - left < 3) return mint(0);
  int mid = (left + right) / 2;
  mint res = online_convolution(S, left, mid) + online_convolution(S, mid, right);
  vector<mint> U(mid-left), G(right-mid);
  for (int i=left; i<mid; i++) {
    if (S[i] == '?') U[i-left] = mint(1);
    else if (S[i] == 'U') U[i-left] = mint(3);
  }
  for (int i=mid; i<right; i++) {
    if (S[i] == '?') G[i-mid] = mint(1);
    else if (S[i] == 'G') G[i-mid] = mint(3);
  }
  auto C = convolution(U, G);
  for (int j=left; j<right; j++) {
    if (S[j] != '?' && S[j] != 'M') continue;
    int j2 = j*2 - left - mid;
    if (j2 < 0 || j2 >= C.size()) continue;
    mint fac = mint(1);
    if (S[j] == 'M') fac = mint(3);
    res += fac * C[j2];
  }
  return res;
}

int main() {
  string S; cin >> S;
  int K = 0;
  for (auto c : S) K += (c == '?' ? 1 : 0);
  mint k = mint(1);
  if (K < 3) {
    for (int i=0; i<3-K; i++) k /= mint(3);
  } else {
    k = mint(3).pow(K-3);
  }
  mint ans = online_convolution(S, 0, (int)S.size()) * k;
  cout << ans.val() << endl;
}
accuracy: 1
time_ms: 150
memory_kb: 6884
final_rank: 1

code_snippet: #include<bits/stdc++.h>
using ll = long long;
#define var auto
const char newl = '\n';

using namespace std;

template<typename T1, typename T2> inline void chmin(T1& a, T2 b) { if (a > b) a = b; }
template<typename T1, typename T2> inline void chmax(T1& a, T2 b) { if (a < b) a = b; }


template<typename T, T MOD = 1000000007>
struct Mint {
  static constexpr T mod = MOD;
  T v;
  Mint() :v(0) {}
  Mint(signed v) :v(v) {}
  Mint(long long t) { v = t % MOD; if (v < 0) v += MOD; }

  Mint pow(long long k) {
    Mint res(1), tmp(v);
    while (k) {
      if (k & 1) res *= tmp;
      tmp *= tmp;
      k >>= 1;
    }
    return res;
  }

  static Mint add_identity() { return Mint(0); }
  static Mint mul_identity() { return Mint(1); }

  Mint inv() { return pow(MOD - 2); }

  Mint& operator+=(Mint a) { v += a.v; if (v >= MOD)v -= MOD; return *this; }
  Mint& operator-=(Mint a) { v += MOD - a.v; if (v >= MOD)v -= MOD; return *this; }
  Mint& operator*=(Mint a) { v = 1LL * v * a.v % MOD; return *this; }
  Mint& operator/=(Mint a) { return (*this) *= a.inv(); }

  Mint operator+(Mint a) const { return Mint(v) += a; }
  Mint operator-(Mint a) const { return Mint(v) -= a; }
  Mint operator*(Mint a) const { return Mint(v) *= a; }
  Mint operator/(Mint a) const { return Mint(v) /= a; }

  Mint operator-() const { return v ? Mint(MOD - v) : Mint(v); }

  bool operator==(const Mint a)const { return v == a.v; }
  bool operator!=(const Mint a)const { return v != a.v; }
  bool operator <(const Mint a)const { return v < a.v; }

  static Mint comb(long long n, int k) {
    Mint num(1), dom(1);
    for (int i = 0; i < k; i++) {
      num *= Mint(n - i);
      dom *= Mint(i + 1);
    }
    return num / dom;
  }
};
template<typename T, T MOD> constexpr T Mint<T, MOD>::mod;
template<typename T, T MOD>
ostream& operator<<(ostream& os, Mint<T, MOD> m) { os << m.v; return os; }


constexpr int bmds(int x) {
  const int v[] = { 1012924417, 924844033, 998244353,
                   897581057, 645922817 };
  return v[x];
}
constexpr int brts(int x) {
  const int v[] = { 5, 5, 3, 3, 3 };
  return v[x];
}

template<int X>
struct NTT {
  static constexpr int md = bmds(X);
  static constexpr int rt = brts(X);
  using M = Mint<int, md>;
  vector< vector<M> > rts, rrts;

  void ensure_base(int n) {
    if ((int)rts.size() >= n) return;
    rts.resize(n); rrts.resize(n);
    for (int i = 1; i < n; i <<= 1) {
      if (!rts[i].empty()) continue;
      M w = M(rt).pow((md - 1) / (i << 1));
      M rw = w.inv();
      rts[i].resize(i); rrts[i].resize(i);
      rts[i][0] = M(1); rrts[i][0] = M(1);
      for (int k = 1; k < i; k++) {
        rts[i][k] = rts[i][k - 1] * w;
        rrts[i][k] = rrts[i][k - 1] * rw;
      }
    }
  }

  void ntt(vector<M>& as, bool f) {
    int n = as.size();
    assert((n & (n - 1)) == 0);
    ensure_base(n);

    for (int i = 0, j = 1; j + 1 < n; j++) {
      for (int k = n >> 1; k > (i ^= k); k >>= 1);
      if (i > j) swap(as[i], as[j]);
    }

    for (int i = 1; i < n; i <<= 1) {
      for (int j = 0; j < n; j += i * 2) {
        for (int k = 0; k < i; k++) {
          M z = as[i + j + k] * (f ? rrts[i][k] : rts[i][k]);
          as[i + j + k] = as[j + k] - z;
          as[j + k] += z;
        }
      }
    }

    if (f) {
      M tmp = M(n).inv();
      for (int i = 0; i < n; i++) as[i] *= tmp;
    }
  }

  vector<M> multiply(vector<M> as, vector<M> bs) {
    int need = as.size() + bs.size() - 1;
    int sz = 1;
    while (sz < need) sz <<= 1;
    as.resize(sz, M(0));
    bs.resize(sz, M(0));

    ntt(as, 0); ntt(bs, 0);
    for (int i = 0; i < sz; i++) as[i] *= bs[i];
    ntt(as, 1);

    as.resize(need);
    return as;
  }

  vector<int> multiply(vector<int> as, vector<int> bs) {
    vector<M> am(as.size()), bm(bs.size());
    for (int i = 0; i < (int)am.size(); i++) am[i] = M(as[i]);
    for (int i = 0; i < (int)bm.size(); i++) bm[i] = M(bs[i]);
    vector<M> cm = multiply(am, bm);
    vector<int> cs(cm.size());
    for (int i = 0; i < (int)cs.size(); i++) cs[i] = cm[i].v;
    return cs;
  }
};
template<int X> constexpr int NTT<X>::md;
template<int X> constexpr int NTT<X>::rt;

using M = Mint<int, 998244353>;
using NTT_998244353 = NTT<2>;

int main() {
  string s;
  cin >> s;
  int n = s.size();
  s.resize(n * 2);
  NTT_998244353 ntt;
  M res = 0;
  for (int bsize = 2; bsize <= n; bsize *= 2) {
    for (int begin = 0; begin < n; begin += bsize * 2) {
      vector<int> u(bsize * 2);
      vector<int> m(bsize * 2);
      vector<int> g(bsize * 2);
      int offset = begin;
      for (int i = 0; i < bsize; i++) {
        if (s[i + offset] == '?') u[i]++;
        if (s[i + offset] == 'U') u[i] += 3;
      }
      for (int i = 0; i < bsize * 2; i++) {
        if (s[i + offset] == '?') m[i]++;
        if (s[i + offset] == 'M') m[i] += 3;
      }
      for (int i = bsize; i < bsize * 2; i++) {
        if (s[i + offset] == '?') g[i]++;
        if (s[i + offset] == 'G') g[i] += 3;
      }
      var ug = ntt.multiply(u, g);
      for (int i = 0; i < bsize * 2; i++) {
        res += ug[i * 2] * m[i];
      }
    }
  }
  var cnt = count(s.begin(), s.end(), '?');
  var mul = M(3).pow(cnt) / M(3).pow(3);
  cout << res * mul << endl;
}
accuracy: 1
time_ms: 400
memory_kb: 50576
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }

#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl
template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, vector<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }
template<class T> ostream& operator << (ostream &s, set<T> P)
{ for(auto it : P) { s << "<" << it << "> "; } return s << endl; }
template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)
{ for(auto it : P) { s << "<" << it.first << "->" << it.second << "> "; } return s << endl; }

// modint
template<int MOD> struct Fp {
    long long val;
    constexpr Fp(long long v = 0) noexcept : val(v % MOD) {
        if (val < 0) val += MOD;
    }
    constexpr int getmod() const { return MOD; }
    constexpr Fp operator - () const noexcept {
        return val ? MOD - val : 0;
    }
    constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r; }
    constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r; }
    constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r; }
    constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r; }
    constexpr Fp& operator += (const Fp& r) noexcept {
        val += r.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }
    constexpr Fp& operator -= (const Fp& r) noexcept {
        val -= r.val;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr Fp& operator *= (const Fp& r) noexcept {
        val = val * r.val % MOD;
        return *this;
    }
    constexpr Fp& operator /= (const Fp& r) noexcept {
        long long a = r.val, 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);
        }
        val = val * u % MOD;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr bool operator == (const Fp& r) const noexcept {
        return this->val == r.val;
    }
    constexpr bool operator != (const Fp& r) const noexcept {
        return this->val != r.val;
    }
    friend constexpr istream& operator >> (istream& is, Fp<MOD>& x) noexcept {
        is >> x.val;
        x.val %= MOD;
        if (x.val < 0) x.val += MOD;
        return is;
    }
    friend constexpr ostream& operator << (ostream& os, const Fp<MOD>& x) noexcept {
        return os << x.val;
    }
    friend constexpr Fp<MOD> modpow(const Fp<MOD>& r, long long n) noexcept {
        if (n == 0) return 1;
        if (n < 0) return modpow(modinv(r), -n);
        auto t = modpow(r, n / 2);
        t = t * t;
        if (n & 1) t = t * r;
        return t;
    }
    friend constexpr Fp<MOD> modinv(const Fp<MOD>& r) noexcept {
        long long a = r.val, 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 Fp<MOD>(u);
    }
};

namespace NTT {
    long long modpow(long long a, long long n, int mod) {
        long long res = 1;
        while (n > 0) {
            if (n & 1) res = res * a % mod;
            a = a * a % mod;
            n >>= 1;
        }
        return res;
    }

    long long modinv(long long a, int mod) {
        long long 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);
        }
        u %= mod;
        if (u < 0) u += mod;
        return u;
    }

    int calc_primitive_root(int mod) {
        if (mod == 2) return 1;
        if (mod == 167772161) return 3;
        if (mod == 469762049) return 3;
        if (mod == 754974721) return 11;
        if (mod == 998244353) return 3;
        int divs[20] = {};
        divs[0] = 2;
        int cnt = 1;
        long long x = (mod - 1) / 2;
        while (x % 2 == 0) x /= 2;
        for (long long i = 3; i * i <= x; i += 2) {
            if (x % i == 0) {
                divs[cnt++] = i;
                while (x % i == 0) x /= i;
            }
        }
        if (x > 1) divs[cnt++] = x;
        for (int g = 2;; g++) {
            bool ok = true;
            for (int i = 0; i < cnt; i++) {
                if (modpow(g, (mod - 1) / divs[i], mod) == 1) {
                    ok = false;
                    break;
                }
            }
            if (ok) return g;
        }
    }

    int get_fft_size(int N, int M) {
        int size_a = 1, size_b = 1;
        while (size_a < N) size_a <<= 1;
        while (size_b < M) size_b <<= 1;
        return max(size_a, size_b) << 1;
    }

    // number-theoretic transform
    template<class mint> void trans(vector<mint>& v, bool inv = false) {
        if (v.empty()) return;
        int N = (int)v.size();
        int MOD = v[0].getmod();
        int PR = calc_primitive_root(MOD);
        static bool first = true;
        static vector<long long> vbw(30), vibw(30);
        if (first) {
            first = false;
            for (int k = 0; k < 30; ++k) {
                vbw[k] = modpow(PR, (MOD - 1) >> (k + 1), MOD);
                vibw[k] = modinv(vbw[k], MOD);
            }
        }
        for (int i = 0, j = 1; j < N - 1; j++) {
            for (int k = N >> 1; k > (i ^= k); k >>= 1);
            if (i > j) swap(v[i], v[j]);
        }
        for (int k = 0, t = 2; t <= N; ++k, t <<= 1) {
            long long bw = vbw[k];
            if (inv) bw = vibw[k];
            for (int i = 0; i < N; i += t) {
                mint w = 1;
                for (int j = 0; j < t/2; ++j) {
                    int j1 = i + j, j2 = i + j + t/2;
                    mint c1 = v[j1], c2 = v[j2] * w;
                    v[j1] = c1 + c2;
                    v[j2] = c1 - c2;
                    w *= bw;
                }
            }
        }
        if (inv) {
            long long invN = modinv(N, MOD);
            for (int i = 0; i < N; ++i) v[i] = v[i] * invN;
        }
    }

    // for garner
    static constexpr int MOD0 = 754974721;
    static constexpr int MOD1 = 167772161;
    static constexpr int MOD2 = 469762049;
    using mint0 = Fp<MOD0>;
    using mint1 = Fp<MOD1>;
    using mint2 = Fp<MOD2>;
    static const mint1 imod0 = 95869806; // modinv(MOD0, MOD1);
    static const mint2 imod1 = 104391568; // modinv(MOD1, MOD2);
    static const mint2 imod01 = 187290749; // imod1 / MOD0;

    // small case (T = mint, long long)
    template<class T> vector<T> naive_mul 
    (const vector<T>& A, const vector<T>& B) {
        if (A.empty() || B.empty()) return {};
        int N = (int)A.size(), M = (int)B.size();
        vector<T> res(N + M - 1);
        for (int i = 0; i < N; ++i)
            for (int j = 0; j < M; ++j)
                res[i + j] += A[i] * B[j];
        return res;
    }

    // mint
    template<class mint> vector<mint> mul
    (const vector<mint>& A, const vector<mint>& B) {
        if (A.empty() || B.empty()) return {};
        int N = (int)A.size(), M = (int)B.size();
        if (min(N, M) < 30) return naive_mul(A, B);
        int MOD = A[0].getmod();
        int size_fft = get_fft_size(N, M);
        if (MOD == 998244353) {
            vector<mint> a(size_fft), b(size_fft), c(size_fft);
            for (int i = 0; i < N; ++i) a[i] = A[i];
            for (int i = 0; i < M; ++i) b[i] = B[i];
            trans(a), trans(b);
            vector<mint> res(size_fft);
            for (int i = 0; i < size_fft; ++i) res[i] = a[i] * b[i];
            trans(res, true);
            res.resize(N + M - 1);
            return res;
        }
        vector<mint0> a0(size_fft, 0), b0(size_fft, 0), c0(size_fft, 0);
        vector<mint1> a1(size_fft, 0), b1(size_fft, 0), c1(size_fft, 0);
        vector<mint2> a2(size_fft, 0), b2(size_fft, 0), c2(size_fft, 0);
        for (int i = 0; i < N; ++i)
            a0[i] = A[i].val, a1[i] = A[i].val, a2[i] = A[i].val;
        for (int i = 0; i < M; ++i)
            b0[i] = B[i].val, b1[i] = B[i].val, b2[i] = B[i].val;
        trans(a0), trans(a1), trans(a2), trans(b0), trans(b1), trans(b2);
        for (int i = 0; i < size_fft; ++i) {
            c0[i] = a0[i] * b0[i];
            c1[i] = a1[i] * b1[i];
            c2[i] = a2[i] * b2[i];
        }
        trans(c0, true), trans(c1, true), trans(c2, true);
        static const mint mod0 = MOD0, mod01 = mod0 * MOD1;
        vector<mint> res(N + M - 1);
        for (int i = 0; i < N + M - 1; ++i) {
            int y0 = c0[i].val;
            int y1 = (imod0 * (c1[i] - y0)).val;
            int y2 = (imod01 * (c2[i] - y0) - imod1 * y1).val;
            res[i] = mod01 * y2 + mod0 * y1 + y0;
        }
        return res;
    }

    // long long
    vector<long long> mul_ll
    (const vector<long long>& A, const vector<long long>& B) {
        if (A.empty() || B.empty()) return {};
        int N = (int)A.size(), M = (int)B.size();
        if (min(N, M) < 30) return naive_mul(A, B);
        int size_fft = get_fft_size(N, M);
        vector<mint0> a0(size_fft, 0), b0(size_fft, 0), c0(size_fft, 0);
        vector<mint1> a1(size_fft, 0), b1(size_fft, 0), c1(size_fft, 0);
        vector<mint2> a2(size_fft, 0), b2(size_fft, 0), c2(size_fft, 0);
        for (int i = 0; i < N; ++i)
            a0[i] = A[i], a1[i] = A[i], a2[i] = A[i];
        for (int i = 0; i < M; ++i)
            b0[i] = B[i], b1[i] = B[i], b2[i] = B[i];
        trans(a0), trans(a1), trans(a2), trans(b0), trans(b1), trans(b2);
        for (int i = 0; i < size_fft; ++i) {
            c0[i] = a0[i] * b0[i];
            c1[i] = a1[i] * b1[i];
            c2[i] = a2[i] * b2[i];
        }
        trans(c0, true), trans(c1, true), trans(c2, true);
        static const long long mod0 = MOD0, mod01 = mod0 * MOD1;
        vector<long long> res(N + M - 1);
        for (int i = 0; i < N + M - 1; ++i) {
            int y0 = c0[i].val;
            int y1 = (imod0 * (c1[i] - y0)).val;
            int y2 = (imod01 * (c2[i] - y0) - imod1 * y1).val;
            res[i] = mod01 * y2 + mod0 * y1 + y0;
        }
        return res;
    }
};

// Binomial Coefficient
template<class T> struct BiCoef {
    vector<T> fact_, inv_, finv_;
    constexpr BiCoef() {}
    constexpr BiCoef(int n) noexcept : fact_(n, 1), inv_(n, 1), finv_(n, 1) {
        init(n);
    }
    constexpr void init(int n) noexcept {
        fact_.assign(n, 1), inv_.assign(n, 1), finv_.assign(n, 1);
        int MOD = fact_[0].getmod();
        for(int i = 2; i < n; i++){
            fact_[i] = fact_[i-1] * i;
            inv_[i] = -inv_[MOD%i] * (MOD/i);
            finv_[i] = finv_[i-1] * inv_[i];
        }
    }
    constexpr T com(int n, int k) const noexcept {
        if (n < k || n < 0 || k < 0) return 0;
        return fact_[n] * finv_[k] * finv_[n-k];
    }
    constexpr T fact(int n) const noexcept {
        if (n < 0) return 0;
        return fact_[n];
    }
    constexpr T inv(int n) const noexcept {
        if (n < 0) return 0;
        return inv_[n];
    }
    constexpr T finv(int n) const noexcept {
        if (n < 0) return 0;
        return finv_[n];
    }
};

// Formal Power Series
template <typename mint> struct FPS : vector<mint> {
    using vector<mint>::vector;
 
    // constructor
    FPS(const vector<mint>& r) : vector<mint>(r) {}
 
    // core operator
    inline FPS pre(int siz) const {
        return FPS(begin(*this), begin(*this) + min((int)this->size(), siz));
    }
    inline FPS rev() const {
        FPS res = *this;
        reverse(begin(res), end(res));
        return res;
    }
    inline FPS& normalize() {
        while (!this->empty() && this->back() == 0) this->pop_back();
        return *this;
    }
 
    // basic operator
    inline FPS operator - () const noexcept {
        FPS res = (*this);
        for (int i = 0; i < (int)res.size(); ++i) res[i] = -res[i];
        return res;
    }
    inline FPS operator + (const mint& v) const { return FPS(*this) += v; }
    inline FPS operator + (const FPS& r) const { return FPS(*this) += r; }
    inline FPS operator - (const mint& v) const { return FPS(*this) -= v; }
    inline FPS operator - (const FPS& r) const { return FPS(*this) -= r; }
    inline FPS operator * (const mint& v) const { return FPS(*this) *= v; }
    inline FPS operator * (const FPS& r) const { return FPS(*this) *= r; }
    inline FPS operator / (const mint& v) const { return FPS(*this) /= v; }
    inline FPS operator << (int x) const { return FPS(*this) <<= x; }
    inline FPS operator >> (int x) const { return FPS(*this) >>= x; }
    inline FPS& operator += (const mint& v) {
        if (this->empty()) this->resize(1);
        (*this)[0] += v;
        return *this;
    }
    inline FPS& operator += (const FPS& r) {
        if (r.size() > this->size()) this->resize(r.size());
        for (int i = 0; i < (int)r.size(); ++i) (*this)[i] += r[i];
        return this->normalize();
    }
    inline FPS& operator -= (const mint& v) {
        if (this->empty()) this->resize(1);
        (*this)[0] -= v;
        return *this;
    }
    inline FPS& operator -= (const FPS& r) {
        if (r.size() > this->size()) this->resize(r.size());
        for (int i = 0; i < (int)r.size(); ++i) (*this)[i] -= r[i];
        return this->normalize();
    }
    inline FPS& operator *= (const mint& v) {
        for (int i = 0; i < (int)this->size(); ++i) (*this)[i] *= v;
        return *this;
    }
    inline FPS& operator *= (const FPS& r) {
        return *this = NTT::mul((*this), r);
    }
    inline FPS& operator /= (const mint& v) {
        assert(v != 0);
        mint iv = modinv(v);
        for (int i = 0; i < (int)this->size(); ++i) (*this)[i] *= iv;
        return *this;
    }
    inline FPS& operator <<= (int x) {
        FPS res(x, 0);
        res.insert(res.end(), begin(*this), end(*this));
        return *this = res;
    }
    inline FPS& operator >>= (int x) {
        FPS res;
        res.insert(res.end(), begin(*this) + x, end(*this));
        return *this = res;
    }
    inline mint eval(const mint& v){
        mint res = 0;
        for (int i = (int)this->size()-1; i >= 0; --i) {
            res *= v;
            res += (*this)[i];
        }
        return res;
    }
    inline friend FPS gcd(const FPS& f, const FPS& g) {
        if (g.empty()) return f;
        return gcd(g, f % g);
    }

    // advanced operation
    // df/dx
    inline friend FPS diff(const FPS& f) {
        int n = (int)f.size();
        FPS res(n-1);
        for (int i = 1; i < n; ++i) res[i-1] = f[i] * i;
        return res;
    }

    // \int f dx
    inline friend FPS integral(const FPS& f) {
        int n = (int)f.size();
        FPS res(n+1, 0);
        for (int i = 0; i < n; ++i) res[i+1] = f[i] / (i+1);
        return res;
    }

    // inv(f), f[0] must not be 0
    inline friend FPS inv(const FPS& f, int deg) {
        assert(f[0] != 0);
        if (deg < 0) deg = (int)f.size();
        FPS res({mint(1) / f[0]});
        for (int i = 1; i < deg; i <<= 1) {
            res = (res + res - res * res * f.pre(i << 1)).pre(i << 1);
        }
        res.resize(deg);
        return res;
    }
    inline friend FPS inv(const FPS& f) {
        return inv(f, f.size());
    }

    // division, r must be normalized (r.back() must not be 0)
    inline FPS& operator /= (const FPS& r) {
        assert(!r.empty());
        assert(r.back() != 0);
        this->normalize();
        if (this->size() < r.size()) {
            this->clear();
            return *this;
        }
        int need = (int)this->size() - (int)r.size() + 1;
        *this = ((*this).rev().pre(need) * inv(r.rev(), need)).pre(need).rev();
        return *this;
    }
    inline FPS& operator %= (const FPS &r) {
        assert(!r.empty());
        assert(r.back() != 0);
        this->normalize();
        FPS q = (*this) / r;
        return *this -= q * r;
    }
    inline FPS operator / (const FPS& r) const { return FPS(*this) /= r; }
    inline FPS operator % (const FPS& r) const { return FPS(*this) %= r; }

    // log(f) = \int f'/f dx, f[0] must be 1
    inline friend FPS log(const FPS& f, int deg) {
        assert(f[0] == 1);
        FPS res = integral(diff(f) * inv(f, deg));
        res.resize(deg);
        return res;
    }
    inline friend FPS log(const FPS& f) {
        return log(f, f.size());
    }

    // exp(f), f[0] must be 0
    inline friend FPS exp(const FPS& f, int deg) {
        assert(f[0] == 0);
        FPS res(1, 1);
        for (int i = 1; i < deg; i <<= 1) {
            res = res * (f.pre(i<<1) - log(res, i<<1) + 1).pre(i<<1);
        }
        res.resize(deg);
        return res;
    }
    inline friend FPS exp(const FPS& f) {
        return exp(f, f.size());
    }

    // pow(f) = exp(e * log f)
    inline friend FPS pow(const FPS& f, long long e, int deg) {
        long long i = 0;
        while (i < (int)f.size() && f[i] == 0) ++i;
        if (i == (int)f.size()) return FPS(deg, 0);
        if (i * e >= deg) return FPS(deg, 0);
        mint k = f[i];
        FPS res = exp(log((f >> i) / k) * e) * modpow(k, e) << (e * i);
        res.resize(deg);
        return res;
    }
    inline friend FPS pow(const FPS& f, long long e) {
        return pow(f, e, f.size());
    }

    // sqrt(f), f[0] must be 1
    inline friend FPS sqrt_base(const FPS& f, int deg) {
        assert(f[0] == 1);
        mint inv2 = mint(1) / 2;
        FPS res(1, 1);
        for (int i = 1; i < deg; i <<= 1) {
            res = (res + f.pre(i << 1) * inv(res, i << 1)).pre(i << 1);
            for (mint& x : res) x *= inv2;
        }
        res.resize(deg);
        return res;
    }
    inline friend FPS sqrt_base(const FPS& f) {
        return sqrt_base(f, f.size());
    }
};

const int MOD = 998244353;
using mint = Fp<MOD>;

mint solve(const string &S, int left, int right) {
    if (right - left < 3) return 0;

    int mid = (left + right) / 2;
    mint res = solve(S, left, mid) + solve(S, mid, right);

    FPS<mint> U(mid - left, 0), G(right - mid, 0);
    for (int i = left; i < mid; ++i) {
        if (S[i] == '?') U[i-left] = 1;
        else if (S[i] == 'U') U[i-left] = 3;
    }
    for (int i = mid; i < right; ++i) {
        if (S[i] == '?') G[i-mid] = 1;
        else if (S[i] == 'G') G[i-mid] = 3;
    }
    auto C = U * G;
    for (int j = left; j < right; ++j) {
        if (S[j] != '?' && S[j] != 'M') continue;
        int j2 = j*2 - left - mid;
        if (j2 < 0 || j2 >= C.size()) continue;
        mint fac = 1;
        if (S[j] == 'M') fac = 3;
        res += fac * C[j2];
    }
    return res;
}

int main() {
    string S;
    cin >> S;
    int K = 0;
    for (auto c : S) if (c == '?') ++K;
    cout << solve(S, 0, S.size()) * modpow(mint(3), K-3) << endl;
}
accuracy: 1
time_ms: 270
memory_kb: 13836
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template <class T, class U> using Pa = pair<T, U>;
template <class T> using vec = vector<T>;
template <class T> using vvec = vector<vec<T>>;

template<ll mod>
struct ModInt {
    ll x;

    ModInt() : x(0) {}

    ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

    ModInt &operator+=(const ModInt &p) {
        if((x += p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator-=(const ModInt &p) {
        if((x += mod - p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator*=(const ModInt &p) {
        x = (1LL * x * p.x % mod);
        return *this;
    }

    ModInt &operator/=(const ModInt &p) {
        *this *= p.inverse();
        return *this;
    }

    ModInt operator-() const { return ModInt(-x); }

    ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }

    ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }

    ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }

    ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }

    bool operator==(const ModInt &p) const { return x == p.x; }

    bool operator!=(const ModInt &p) const { return x != p.x; }

    ModInt inverse() const {
        ll a = x, b = mod, u = 1, v = 0, t;
        while(b > 0) {
        t = a / b;
        swap(a -= t * b, b);
        swap(u -= t * v, v);
        }
        return ModInt(u);
    }

    ModInt pow(int64_t n) const {
        ModInt ret(1), mul(x);
        while(n > 0) {
        if(n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const ModInt &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, ModInt &a) {
        int64_t t;
        is >> t;
        a = ModInt<mod>(t);
        return (is);
    }

    static ll get_mod() { return mod; }
};

using mint = ModInt<998244353>;

namespace FastFourierTransform {
    using real = double;

    struct C {
        real x, y;

        C() : x(0), y(0) {}

        C(real x, real y) : x(x), y(y) {}

        inline C operator+(const C &c) const { return C(x + c.x, y + c.y); }

        inline C operator-(const C &c) const { return C(x - c.x, y - c.y); }

        inline C operator*(const C &c) const { return C(x * c.x - y * c.y, x * c.y + y * c.x); }

        inline C conj() const { return C(x, -y); }
    };

    const real PI = acosl(-1);
    int base = 1;
    vector< C > rts = { {0, 0},
                        {1, 0} };
    vector< int > rev = {0, 1};


    void ensure_base(int nbase) {
        if(nbase <= base) return;
        rev.resize(1 << nbase);
        rts.resize(1 << nbase);
        for(int i = 0; i < (1 << nbase); i++) {
            rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
        }
        while(base < nbase) {
            real angle = PI * 2.0 / (1 << (base + 1));
            for(int i = 1 << (base - 1); i < (1 << base); i++) {
                rts[i << 1] = rts[i];
                real angle_i = angle * (2 * i + 1 - (1 << base));
                rts[(i << 1) + 1] = C(cos(angle_i), sin(angle_i));
            }
            ++base;
        }
    }

    void fft(vector< C > &a, int n) {
        assert((n & (n - 1)) == 0);
        int zeros = __builtin_ctz(n);
        ensure_base(zeros);
        int shift = base - zeros;
        for(int i = 0; i < n; i++) {
            if(i < (rev[i] >> shift)) {
                swap(a[i], a[rev[i] >> shift]);
            }
        }
        for(int k = 1; k < n; k <<= 1) {
            for(int i = 0; i < n; i += 2 * k) {
                for(int j = 0; j < k; j++) {
                    C z = a[i + j + k] * rts[j + k];
                    a[i + j + k] = a[i + j] - z;
                    a[i + j] = a[i + j] + z;
                }
            }
        }
    }

    vector< int64_t > multiply(const vector< int > &a, const vector< int > &b) {
        int need = (int) a.size() + (int) b.size() - 1;
        int nbase = 1;
        while((1 << nbase) < need) nbase++;
        ensure_base(nbase);
        int sz = 1 << nbase;
        vector< C > fa(sz);
        for(int i = 0; i < sz; i++) {
            int x = (i < (int) a.size() ? a[i] : 0);
            int y = (i < (int) b.size() ? b[i] : 0);
            fa[i] = C(x, y);
        }
        fft(fa, sz);
        C r(0, -0.25 / (sz >> 1)), s(0, 1), t(0.5, 0);
        for(int i = 0; i <= (sz >> 1); i++) {
            int j = (sz - i) & (sz - 1);
            C z = (fa[j] * fa[j] - (fa[i] * fa[i]).conj()) * r;
            fa[j] = (fa[i] * fa[i] - (fa[j] * fa[j]).conj()) * r;
            fa[i] = z;
        }
        for(int i = 0; i < (sz >> 1); i++) {
            C A0 = (fa[i] + fa[i + (sz >> 1)]) * t;
            C A1 = (fa[i] - fa[i + (sz >> 1)]) * t * rts[(sz >> 1) + i];
            fa[i] = A0 + A1 * s;
        }
        fft(fa, sz >> 1);
        vector< int64_t > ret(need);
        for(int i = 0; i < need; i++) {
            ret[i] = llround(i & 1 ? fa[i >> 1].y : fa[i >> 1].x);
        }
        return ret;
    }
};

template< typename T >
struct ArbitraryModConvolution {
    using real = FastFourierTransform::real;
    using C = FastFourierTransform::C;

    ArbitraryModConvolution() = default;

    vector< T > multiply(const vector< T > &a, const vector< T > &b, int need = -1) {
        if(need == -1) need = a.size() + b.size() - 1;
        int nbase = 0;
        while((1 << nbase) < need) nbase++;
        FastFourierTransform::ensure_base(nbase);
        int sz = 1 << nbase;
        vector< C > fa(sz);
        for(int i = 0; i < a.size(); i++) {
            fa[i] = C(a[i].x & ((1 << 15) - 1), a[i].x >> 15);
        }
        fft(fa, sz);
        vector< C > fb(sz);
        if(a == b) {
            fb = fa;
        }else{
            for(int i = 0; i < b.size(); i++) {
                fb[i] = C(b[i].x & ((1 << 15) - 1), b[i].x >> 15);
            }
            fft(fb, sz);
        }
        real ratio = 0.25 / sz;
        C r2(0, -1), r3(ratio, 0), r4(0, -ratio), r5(0, 1);
        for(int i = 0; i <= (sz >> 1); i++) {
            int j = (sz - i) & (sz - 1);
            C a1 = (fa[i] + fa[j].conj());
            C a2 = (fa[i] - fa[j].conj()) * r2;
            C b1 = (fb[i] + fb[j].conj()) * r3;
            C b2 = (fb[i] - fb[j].conj()) * r4;
            if(i != j) {
                C c1 = (fa[j] + fa[i].conj());
                C c2 = (fa[j] - fa[i].conj()) * r2;
                C d1 = (fb[j] + fb[i].conj()) * r3;
                C d2 = (fb[j] - fb[i].conj()) * r4;
                fa[i] = c1 * d1 + c2 * d2 * r5;
                fb[i] = c1 * d2 + c2 * d1;
            }
            fa[j] = a1 * b1 + a2 * b2 * r5;
            fb[j] = a1 * b2 + a2 * b1;
        }
        fft(fa, sz);
        fft(fb, sz);
        vector< T > ret(need);
        for(int i = 0; i < need; i++) {
            int64_t aa = llround(fa[i].x);
            int64_t bb = llround(fb[i].x);
            int64_t cc = llround(fa[i].y);
            aa = T(aa).x, bb = T(bb).x, cc = T(cc).x;
            ret[i] = aa + (bb << 15) + (cc << 30);
        }
        return ret;
    }
};


int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    string S;
    cin >> S;
    int N = S.size();
    int cnt = 0;
    for(int i=0;i<N;i++) cnt += S[i]=='?';
    ArbitraryModConvolution<mint> AMC;
    mint three = 3;
    mint inv3 = three.inverse();
    //[l,m),[m,r)
    auto calc = [&](int l,int m,int r)->mint{
        if(r-l<3) return 0;
        int n = r-l;
        vec<mint> U(n),G(n);
        for(int i=l;i<m;i++){
            if(S[i]=='U') U[i-l] = 1;
            if(S[i]=='?') U[i-l] = inv3;
        }
        for(int i=m;i<r;i++){
            if(S[i]=='G') G[i-l] = 1;
            if(S[i]=='?') G[i-l] = inv3;
        }
        auto R = AMC.multiply(U,G);
        mint res = 0;
        for(int i=l;i<r;i++){
            if(S[i]=='M') res += R[2*(i-l)];
            if(S[i]=='?') res += R[2*(i-l)]*inv3;
        }
        return res;
    };

    auto divide = [&](auto&& self,int l,int r)->mint{
        if(r-l<3) return 0;
        mint res = 0;
        int m = (l+r)/2;
        res += self(self,l,m)+self(self,m,r);
        res += calc(l,m,r);
        return res;
    };

    mint ans = divide(divide,0,N)*three.pow(cnt);
    cout << ans << "\n";
}
accuracy: 1
time_ms: 840
memory_kb: 38416
final_rank: 11

code_snippet: #include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>

#include <iostream>
#include <complex>
#include <string>
#include <algorithm>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>

#include <functional>
#include <cassert>

typedef long long ll;
using namespace std;

#ifndef LOCAL
#define debug(x) ;
#else
#define debug(x) cerr << __LINE__ << " : " << #x << " = " << (x) << endl;

template <typename T1, typename T2>
ostream &operator<<(ostream &out, const pair<T1, T2> &p) {
  out << "{" << p.first << ", " << p.second << "}";
  return out;
}

template <typename T>
ostream &operator<<(ostream &out, const vector<T> &v) {
  out << '{';
  for (const T &item : v) out << item << ", ";
  out << "\b\b}";
  return out;
}
#endif

#define mod 998244353 //1e9+7(prime number)
#define INF 1000000000 //1e9
#define LLINF 2000000000000000000LL //2e18
#define SIZE 200010

ll power(ll k, ll n, int M){
  ll res = 1;
  while(n > 0) {
    if (n & 1) res = res * k % M;
    k = k * k % M;
    n /= 2;
  }
  return res;
}

/* Number Theoretic Transform */

namespace NTT {
  void DFT(int m, int root, vector<int> &a, bool rev = false) {
    int N = a.size();

    for(int i = 0, j = 1; j + 1 < N; j++) {
      for(int k = N >> 1; k > (i ^= k); k >>= 1);
      if(i > j) swap(a[i], a[j]);
    }

    int g = power(root, (mod - 1) / N, mod);
    if (rev) g = power(g, mod - 2, mod);

    for (int i = 1; i < N; i *= 2) {
      int base = power(g, N / i / 2, mod);
      ll w = 1;
      for (int j = 0; j < i; j++) {
        for (int k = 0; k < N; k += i*2) {
          int s = a[j+k], t = a[j+k+i] * w % m;
          a[j+k+0] = (s + t) % m;
          a[j+k+i] = (s - t + m) % m;
        }
        w = w * base % m;
      }
    }

    if (rev) {
      ll tmp = power(N, m-2, m);
      for(int &v : a) v = v * tmp % m;
    }
  }

  // (469762049, 3), (924844033, 5), (998244353, 3), (1012924417, 5)

  vector<int> conv(int _mod, int root, const vector<int> &a, const vector<int> &b) {
    int s = 1, t = a.size() + b.size() - 1;
    while(s < t) s *= 2;

    vector<int> F(s), G(s);
    for(int i = 0; i < (int)a.size(); i++) F[i] = a[i];
    for(int i = 0; i < (int)b.size(); i++) G[i] = b[i];
    DFT(_mod, root, F); DFT(_mod, root, G);

    for(int i = 0; i < s; i++) F[i] = (ll)F[i] * G[i] % _mod;
    DFT(_mod, root, F, true);

    return F;
  }
};

int N;
char S[SIZE];
int U[SIZE], M[SIZE], G[SIZE];

ll solve(int l, int r) {
  ll res = 0;

  if(r - l <= 2) return 0;

  vector<int> a(r-l), b(r-l);

  for(int i=l; i<r; i++) {
    if (i < (l+r)/2)
      a[i-l] = U[i];
    else
      b[i-l] = G[i];
  }

  auto UG = NTT::conv(mod, 5, a, b);

  for(int i=0; i<(r-l); i++) {
    res += (ll)UG[i*2] * M[i + l] % mod;
  }

  res += solve(l, (l+r)/2);
  res += solve((l+r)/2, r);

  return res % mod;
}

int main(){

  scanf("%s", S);
  N = strlen(S);

  int questions = 0;

  for (int i=0; i<N; i++)
    questions += S[i] == '?';

  ll base = power(3, questions, mod);
  ll inv3 = power(3, mod - 2, mod);

  for(int i=0; i<N; i++) {
    if(S[i] == 'U') U[i] = base;
    if(S[i] == 'M') M[i] = 1;
    if(S[i] == 'G') G[i] = 1;

    if(S[i] == '?') {
      U[i] = base * inv3 % mod;
      M[i] = G[i] = inv3;
    }
  }

  int ans = solve(0, N);

  printf("%d\n", ans);

  return 0;
}
accuracy: 1
time_ms: 2540
memory_kb: 12468
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


constexpr Int bmds(Int x){
  const Int v[] = {1012924417, 924844033, 998244353,
                   897581057, 645922817};
  return v[x];
}
constexpr Int brts(Int x){
  const Int v[] = {5, 5, 3, 3, 3};
  return v[x];
}


template<Int X>
struct NTT{
  static constexpr Int md = bmds(X);
  static constexpr Int rt = brts(X);

  inline Int add(Int a,Int b){
    a+=b;
    if(a>=md) a-=md;
    return a;
  }

  inline Int mul(Int a,Int b){
    return 1LL*a*b%md;
  }

  inline Int pow(Int a,Int b){
    Int res=1;
    while(b){
      if(b&1) res=mul(res,a);
      a=mul(a,a);
      b>>=1;
    }
    return res;
  }

  inline Int inv(Int x){
    return pow(x,md-2);
  }

  // assume md % 4 = 1
  // if md % 4 == 3, then x = a^{(md+1)/4}
  inline Int sqrt(Int a){
    if(a==0) return 0;
    if(pow(a,(md-1)/2)!=1) return -1;
    Int q=md-1,m=0;
    while(~q&1) q>>=1,m++;
    mt19937 mt;
    Int z=mt()%md;
    while(pow(z,(md-1)/2)!=md-1) z=mt()%md;
    Int c=pow(z,q),t=pow(a,q),r=pow(a,(q+1)/2);
    while(m>1){
      if(pow(t,1<<(m-2))!=1)
        r=mul(r,c),t=mul(t,mul(c,c));
      c=mul(c,c);
      m--;
    }
    return r;
  }

  vector<vector<Int> > rts,rrts;

  void ensure_base(Int n){
    if((Int)rts.size()>=n) return;
    rts.resize(n);rrts.resize(n);
    for(Int i=1;i<n;i<<=1){
      if(!rts[i].empty()) continue;
      Int w=pow(rt,(md-1)/(i<<1));
      Int rw=inv(w);
      rts[i].resize(i);rrts[i].resize(i);
      rts[i][0]=1;rrts[i][0]=1;
      for(Int k=1;k<i;k++){
        rts[i][k]=mul(rts[i][k-1],w);
        rrts[i][k]=mul(rrts[i][k-1],rw);
      }
    }
  }

  void ntt(vector<Int> &a,bool f,Int n=-1){
    if(n==-1) n=a.size();
    assert((n&(n-1))==0);

    for(Int i=0,j=1;j+1<n;j++){
      for(Int k=n>>1;k>(i^=k);k>>=1);
      if(i>j) swap(a[i],a[j]);
    }

    for(Int i=1;i<n;i<<=1){
      for(Int j=0;j<n;j+=i*2){
        for(Int k=0;k<i;k++){
          Int z=mul(a[i+j+k],f?rrts[i][k]:rts[i][k]);
          a[i+j+k]=add(a[j+k],md-z);
          a[j+k]=add(a[j+k],z);
        }
      }
    }

    if(f){
      Int tmp=inv(n);
      for(Int i=0;i<n;i++) a[i]=mul(a[i],tmp);
    }
  }

  vector<Int> add(vector<Int> as,vector<Int> bs){
    Int sz=max(as.size(),bs.size());
    vector<Int> cs(sz,0);
    for(Int i=0;i<(Int)as.size();i++) cs[i]=add(cs[i],as[i]);
    for(Int i=0;i<(Int)bs.size();i++) cs[i]=add(cs[i],bs[i]);
    return cs;
  }

  vector<Int> sub(vector<Int> as,vector<Int> bs){
    Int sz=max(as.size(),bs.size());
    vector<Int> cs(sz,0);
    for(Int i=0;i<(Int)as.size();i++) cs[i]=add(cs[i],as[i]);
    for(Int i=0;i<(Int)bs.size();i++) cs[i]=add(cs[i],md-bs[i]);
    return cs;
  }

  vector<Int> multiply(vector<Int> as,vector<Int> bs){
    Int need=as.size()+bs.size()-1;
    Int sz=1;
    while(sz<need) sz<<=1;
    ensure_base(sz);

    vector<Int> f(sz),g(sz);
    for(Int i=0;i<(Int)as.size();i++) f[i]=as[i];
    for(Int i=0;i<(Int)bs.size();i++) g[i]=bs[i];
    ntt(f,0);ntt(g,0);
    for(Int i=0;i<sz;i++) f[i]=mul(f[i],g[i]);
    ntt(f,1);

    f.resize(need);
    return f;
  }
};


template<typename T,T MOD = 1000000007>
struct Mint{
  static constexpr T mod = MOD;
  T v;
  Mint():v(0){}
  Mint(signed v):v(v){}
  Mint(long long t){v=t%MOD;if(v<0) v+=MOD;}

  Mint pow(long long k){
    Mint res(1),tmp(v);
    while(k){
      if(k&1) res*=tmp;
      tmp*=tmp;
      k>>=1;
    }
    return res;
  }

  static Mint add_identity(){return Mint(0);}
  static Mint mul_identity(){return Mint(1);}

  Mint inv(){return pow(MOD-2);}

  Mint& operator+=(Mint a){v+=a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator-=(Mint a){v+=MOD-a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator*=(Mint a){v=1LL*v*a.v%MOD;return *this;}
  Mint& operator/=(Mint a){return (*this)*=a.inv();}

  Mint operator+(Mint a) const{return Mint(v)+=a;};
  Mint operator-(Mint a) const{return Mint(v)-=a;};
  Mint operator*(Mint a) const{return Mint(v)*=a;};
  Mint operator/(Mint a) const{return Mint(v)/=a;};

  Mint operator-() const{return v?Mint(MOD-v):Mint(v);}

  bool operator==(const Mint a)const{return v==a.v;}
  bool operator!=(const Mint a)const{return v!=a.v;}
  bool operator <(const Mint a)const{return v <a.v;}

};
template<typename T,T MOD> constexpr T Mint<T, MOD>::mod;
template<typename T,T MOD>
ostream& operator<<(ostream &os,Mint<T, MOD> m){os<<m.v;return os;}

//INSERT ABOVE HERE

NTT<2> ntt;
using M = Mint<Int, ntt.md>;
vector<M> res;

void dfs(vector<Int> &as,vector<Int> &bs,Int l,Int r){
  if(r-l==1) return;
  Int m=(l+r)>>1;
  vector<Int> cs(m-l);
  vector<Int> ds(r-m);
  for(Int i=l;i<m;i++) cs[i-l]=as[i];
  for(Int i=m;i<r;i++) ds[i-m]=bs[i];
  auto es=ntt.multiply(cs,ds);
  for(Int i=0;i<(Int)es.size();i++)
    res[l+m+i]+=M(es[i]);
  dfs(as,bs,l,m);
  dfs(as,bs,m,r);
}

signed main(){
  string s;
  cin>>s;
  Int n=s.size();
  vector<Int> us(n),gs(n),qs(n);
  Int num=0;
  for(Int i=0;i<n;i++){
    us[i]=s[i]=='U';
    gs[i]=s[i]=='G';
    qs[i]=s[i]=='?';

    num+=qs[i];
  }

  M ans{0};
  // U (M / ?) G
  {
    res.assign(2*n,0);
    dfs(us,gs,0,n);
    for(Int i=0;i<n;i++){
      if(s[i]=='M'){
        ans+=res[i*2]*M(3).pow(num);
      }
      if(s[i]=='?'){
        ans+=res[i*2]*M(3).pow(num-1);
      }
    }
  }
  // ? (M / ?) G
  {
    res.assign(2*n,0);
    dfs(qs,gs,0,n);
    for(Int i=0;i<n;i++){
      if(s[i]=='M'){
        if(num>=1)
          ans+=res[i*2]*M(3).pow(num-1);
      }
      if(s[i]=='?'){
        if(num>=2)
          ans+=res[i*2]*M(3).pow(num-2);
      }
    }
  }

  // U (M / ?) ?
  {
    res.assign(2*n,0);
    dfs(us,qs,0,n);
    for(Int i=0;i<n;i++){
      if(s[i]=='M'){
        if(num>=1)
          ans+=res[i*2]*M(3).pow(num-1);
      }
      if(s[i]=='?'){
        if(num>=2)
          ans+=res[i*2]*M(3).pow(num-2);
      }
    }
  }

  // ? (M / ?) ?
  {
    res.assign(2*n,0);
    dfs(qs,qs,0,n);
    for(Int i=0;i<n;i++){
      if(s[i]=='M'){
        if(num>=2)
          ans+=res[i*2]*M(3).pow(num-2);
      }
      if(s[i]=='?'){
        if(num>=3)
          ans+=res[i*2]*M(3).pow(num-3);
      }
    }
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 1220
memory_kb: 34880
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;





#include<cmath>
#include<valarray>
#include<iostream>

namespace ProconLib{

    // To commit Zuru
    class GodBitset{
        public:
        using Int=unsigned long long;    
        static constexpr size_t SIZE=sizeof(Int)<<3;
        static constexpr size_t LOG_SIZE=std::log2(SIZE);

        protected:
        const int N;
        const int DatSize;
        const int NmodSIZE;        
        std::valarray<Int> dat;

        public:
        GodBitset(size_t N):N(N),DatSize((N+SIZE-1)/SIZE),dat(DatSize),NmodSIZE(N%SIZE){}
        GodBitset(const GodBitset& obj):N(obj.N),DatSize(obj.DatSize),dat(obj.dat),NmodSIZE(obj.NmodSIZE){}
        GodBitset(const GodBitset&& obj):N(obj.N),DatSize(obj.DatSize),dat(std::move(obj.dat)),NmodSIZE(obj.NmodSIZE){}

        // GodBitset operator~() const {auto tmp=*this; tmp.dat=~tmp.dat; return tmp;}
        GodBitset& operator&=(const GodBitset& rhs){dat&=rhs.dat; return *this;}
        GodBitset& operator|=(const GodBitset& rhs){dat|=rhs.dat; return *this;}
        GodBitset& operator^=(const GodBitset& rhs){dat^=rhs.dat; return *this;}
        GodBitset& operator>>=(int d);
        GodBitset& operator<<=(int d);
        bool get(int pos) const;
        void set(int pos,bool x);
        int size() const {return N;}
        int count() const {int res=0; for(int i=0;i<DatSize;i++) res+=__builtin_popcount(dat[i]); return res;}

        template<class Operator>
        friend int countIf(const GodBitset& lhs,const GodBitset& rhs);
    };

    GodBitset operator&(const GodBitset& lhs,const GodBitset& rhs){auto tmp=lhs; return tmp&=rhs;}
    GodBitset operator|(const GodBitset& lhs,const GodBitset& rhs){auto tmp=lhs; return tmp|=rhs;}
    GodBitset operator^(const GodBitset& lhs,const GodBitset& rhs){auto tmp=lhs; return tmp^=rhs;}
    GodBitset operator<<(const GodBitset& bs,int d){auto tmp=bs; return tmp<<=d;}
    GodBitset operator>>(const GodBitset& bs,int d){auto tmp=bs; return tmp>>=d;}

    GodBitset& GodBitset::operator>>=(int d){
        int diff=d/SIZE;
        int offset=d%SIZE;
        for(int i=0;i+diff+1<DatSize;i++){
            dat[i]=(dat[i+diff]>>offset)|(dat[i+diff+1]<<(SIZE-offset));
        }
        int id=DatSize-diff-1; // id+diff+1==DatSize
        if(0<=id) dat[id]=dat[id+diff]>>offset;
        for(int i=id+1;i<DatSize;i++) dat[i]=0;

        if(NmodSIZE==0) return *this;
        // Int mask=(Int(1)<<NmodSIZE)-1;
        // dat[DatSize]&=mask;
        return *this;
    }

    GodBitset& GodBitset::operator<<=(int d){
        int diff=d/SIZE;
        int offset=d%SIZE;
        for(int i=DatSize-1;i>=diff+1;i--){
            dat[i]=(dat[i-diff]<<offset)|(dat[i-diff-1]>>(SIZE-offset));
        }
        dat[diff]=dat[0]<<offset;
        for(int i=0;i<diff;i++) dat[i]=0;
        return *this;
    }

    bool GodBitset::get(int pos) const{
        int d=pos/SIZE;
        int offset=pos%SIZE;
        return (dat[d]>>offset)&1;
    }

    void GodBitset::set(int pos,bool x){
        int d=pos/SIZE;
        int offset=pos%SIZE;
        if((dat[d]>>offset)&1) dat[d]^=(Int(!x)<<offset);
        else dat[d]^=(Int(x)<<offset);
    }

    std::ostream& operator<<(std::ostream& os,const GodBitset& bs){
        for(int i=bs.size()-1;i>=0;i--){
            os<<bs.get(i);
        }
        return os;
    }

    template<class Operator>
    int countIf(const GodBitset& lhs,const GodBitset& rhs){
        int N=lhs.size();
        int res=0;
        for(int i=0;i<N;i++) res+=Operator::op(lhs,rhs);
        return res;
    }
}

using namespace ProconLib;
const int SIZE=2*1e5+1;
using Bit=GodBitset;

using ll=long long;
const ll MOD=998244353;
constexpr ll powm(ll x,ll k){
    ll res=1;
    while(k){
        if(k&1) res=res*x%MOD;
        k>>=1;
        x=x*x%MOD;
    }
    return res;
}
constexpr ll inv(ll x){
    return powm(x,MOD-2);
}
string s;
int n;
constexpr ll inv3_1=inv(3);
constexpr ll inv3_2=inv3_1*inv3_1%MOD;
constexpr ll inv3_3=inv3_2*inv3_1%MOD;
ll calc(){
    Bit lhsU(SIZE);
    Bit lhsQ(SIZE);
    Bit rhsG(SIZE);
    Bit rhsQ(SIZE);
    ll res=0;
    for(int i=1;i<s.size();i++) if('G'==s[i]) rhsG.set(i-1,true);
    for(int i=1;i<s.size();i++) if('?'==s[i]) rhsQ.set(i-1,true);
    for(int i=0;i<s.size();i++){
        if(s[i]=='M' || s[i]=='?'){
            ll tmp=(lhsU&rhsG).count();
            if(s[i]=='M' && 0<=n) res+=tmp;
            else if(s[i]=='?' && 1<=n) res+=tmp*inv3_1;

            tmp=(lhsU&rhsQ).count();
            if(s[i]=='M' && 1<=n) res+=tmp*inv3_1;
            else if(s[i]=='?' && 2<=n) res+=tmp*inv3_2;

            tmp=(lhsQ&rhsG).count();
            if(s[i]=='M' && 1<=n) res+=tmp*inv3_1;
            else if(s[i]=='?' && 2<=n) res+=tmp*inv3_2%MOD;

            tmp=(lhsQ&rhsQ).count();
            if(s[i]=='M' && 2<=n) res+=tmp*inv3_2;
            else if(s[i]=='?' && 3<=n) res+=tmp*inv3_3;
            res%=MOD;
        }
        lhsU<<=1;
        lhsQ<<=1;
        rhsG>>=1;
        rhsQ>>=1;
        if(s[i]=='U') lhsU.set(0,true);
        if(s[i]=='?') lhsQ.set(0,true);
    }
    return res%MOD;
}

void test(){
    std::cerr<<Bit::SIZE<<std::endl;
    Bit bs(70);
    bs.set(64,1);
    bs.set(63,1);
    bs.set(64,1);
    bs.set(63,0);
    bs.set(2,0);
    cerr<<bs<<endl;
    bs<<=1;
    cerr<<bs<<endl;
    bs>>=1;
    cerr<<bs<<endl;
    bs>>=2;
    cerr<<bs<<endl;
    bs<<=4;
    cerr<<bs<<endl;

}
int main(){
    // test();
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>s;
    n=count(s.begin(),s.end(),'?');
    ll pow3=powm(3,n);
    ll res=pow3*calc()%MOD;
    cout<<res%MOD<<"\n";
    return 0;
}
accuracy: 0.10344827586206896
time_ms: 10
memory_kb: 3312
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;





#include<cmath>
#include<valarray>
#include<iostream>

namespace ProconLib{

    // To commit Zuru
    class GodBitset{
        public:
        using Int=unsigned long long;    
        static constexpr size_t SIZE=sizeof(Int)<<3;
        static constexpr size_t LOG_SIZE=std::log2(SIZE);

        protected:
        const int N;
        const int DatSize;
        const int NmodSIZE;        
        std::valarray<Int> dat;

        public:
        GodBitset(size_t N):N(N),DatSize((N+SIZE-1)/SIZE),dat(DatSize),NmodSIZE(N%SIZE){}
        GodBitset(const GodBitset& obj):N(obj.N),DatSize(obj.DatSize),dat(obj.dat),NmodSIZE(obj.NmodSIZE){}
        GodBitset(const GodBitset&& obj):N(obj.N),DatSize(obj.DatSize),dat(std::move(obj.dat)),NmodSIZE(obj.NmodSIZE){}

        // GodBitset operator~() const {auto tmp=*this; tmp.dat=~tmp.dat; return tmp;}
        GodBitset& operator&=(const GodBitset& rhs){dat&=rhs.dat; return *this;}
        GodBitset& operator|=(const GodBitset& rhs){dat|=rhs.dat; return *this;}
        GodBitset& operator^=(const GodBitset& rhs){dat^=rhs.dat; return *this;}
        GodBitset& operator>>=(int d);
        GodBitset& operator<<=(int d);
        bool get(int pos) const;
        void set(int pos,bool x);
        int size() const {return N;}
        int count() const {int res=0; for(int i=0;i<DatSize;i++) res+=__builtin_popcount(dat[i]); return res;}

        template<class Operator>
        friend int countIf(const GodBitset& lhs,const GodBitset& rhs);
    };

    GodBitset operator&(const GodBitset& lhs,const GodBitset& rhs){auto tmp=lhs; return tmp&=rhs;}
    GodBitset operator|(const GodBitset& lhs,const GodBitset& rhs){auto tmp=lhs; return tmp|=rhs;}
    GodBitset operator^(const GodBitset& lhs,const GodBitset& rhs){auto tmp=lhs; return tmp^=rhs;}
    GodBitset operator<<(const GodBitset& bs,int d){auto tmp=bs; return tmp<<=d;}
    GodBitset operator>>(const GodBitset& bs,int d){auto tmp=bs; return tmp>>=d;}

    GodBitset& GodBitset::operator>>=(int d){
        int diff=d/SIZE;
        int offset=d%SIZE;
        for(int i=0;i+diff+1<DatSize;i++){
            dat[i]=(dat[i+diff]>>offset)|(dat[i+diff+1]<<(SIZE-offset));
        }
        int id=DatSize-diff-1; // id+diff+1==DatSize
        if(0<=id) dat[id]=dat[id+diff]>>offset;
        for(int i=id+1;i<DatSize;i++) dat[i]=0;

        if(NmodSIZE==0) return *this;
        Int mask=(Int(1)<<NmodSIZE)-1;
        dat[DatSize]&=mask;
        return *this;
    }

    GodBitset& GodBitset::operator<<=(int d){
        int diff=d/SIZE;
        int offset=d%SIZE;
        for(int i=DatSize-1;i>=diff+1;i--){
            dat[i]=(dat[i-diff]<<offset)|(dat[i-diff-1]>>(SIZE-offset));
        }
        dat[diff]=dat[0]<<offset;
        for(int i=0;i<diff;i++) dat[i]=0;
        return *this;
    }

    bool GodBitset::get(int pos) const{
        int d=pos/SIZE;
        int offset=pos%SIZE;
        return (dat[d]>>offset)&1;
    }

    void GodBitset::set(int pos,bool x){
        int d=pos/SIZE;
        int offset=pos%SIZE;
        if((dat[d]>>offset)&1) dat[d]|=(Int(!x)<<offset);
        else dat[d]|=(Int(x)<<offset);
    }

    std::ostream& operator<<(std::ostream& os,const GodBitset& bs){
        for(int i=bs.size()-1;i>=0;i--){
            os<<bs.get(i);
        }
        return os;
    }

    template<class Operator>
    int countIf(const GodBitset& lhs,const GodBitset& rhs){
        int N=lhs.size();
        int res=0;
        for(int i=0;i<N;i++) res+=Operator::op(lhs,rhs);
        return res;
    }
}

using namespace ProconLib;
const int SIZE=2*1e5+1;
using Bit=GodBitset;

using ll=long long;
const ll MOD=998244353;
constexpr ll powm(ll x,ll k){
    ll res=1;
    while(k){
        if(k&1) res=res*x%MOD;
        k>>=1;
        x=x*x%MOD;
    }
    return res;
}
constexpr ll inv(ll x){
    return powm(x,MOD-2);
}
string s;
int n;
constexpr ll inv3_1=inv(3);
constexpr ll inv3_2=inv3_1*inv3_1%MOD;
constexpr ll inv3_3=inv3_2*inv3_1%MOD;
ll calc(){
    Bit lhsU(SIZE);
    Bit lhsQ(SIZE);
    Bit rhsG(SIZE);
    Bit rhsQ(SIZE);
    ll res=0;
    for(int i=1;i<s.size();i++) if('G'==s[i]) rhsG.set(i-1,true);
    for(int i=1;i<s.size();i++) if('?'==s[i]) rhsQ.set(i-1,true);
    for(int i=0;i<s.size();i++){
        if(s[i]=='M' || s[i]=='?'){
            ll tmp=(lhsU&rhsG).count();
            if(s[i]=='M' && 0<=n) res+=tmp;
            else if(s[i]=='?' && 1<=n) res+=tmp*inv3_1;

            tmp=(lhsU&rhsQ).count();
            if(s[i]=='M' && 1<=n) res+=tmp*inv3_1;
            else if(s[i]=='?' && 2<=n) res+=tmp*inv3_2;

            tmp=(lhsQ&rhsG).count();
            if(s[i]=='M' && 1<=n) res+=tmp*inv3_1;
            else if(s[i]=='?' && 2<=n) res+=tmp*inv3_2%MOD;

            tmp=(lhsQ&rhsQ).count();
            if(s[i]=='M' && 2<=n) res+=tmp*inv3_2;
            else if(s[i]=='?' && 3<=n) res+=tmp*inv3_3;
            res%=MOD;
        }
        lhsU<<=1;
        lhsQ<<=1;
        rhsG>>=1;
        rhsQ>>=1;
        if(s[i]=='U') lhsU.set(0,true);
        if(s[i]=='?') lhsQ.set(0,true);
    }
    return res%MOD;
}

void test(){
    std::cerr<<Bit::SIZE<<std::endl;
    Bit bs(70);
    bs.set(64,1);
    bs.set(63,1);
    cerr<<bs<<endl;
    bs<<=1;
    cerr<<bs<<endl;
    bs>>=1;
    cerr<<bs<<endl;
    bs>>=2;
    cerr<<bs<<endl;
    bs<<=4;
    cerr<<bs<<endl;

}
int main(){
    // test();
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>s;
    n=count(s.begin(),s.end(),'?');
    ll pow3=powm(3,n);
    ll res=pow3*calc()%MOD;
    cout<<res%MOD<<"\n";
    return 0;
}
accuracy: 0.10344827586206896
time_ms: 10
memory_kb: 3312
final_rank: 19

code_snippet: #include <bits/stdc++.h>
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#define NDEBUG
#define SHOW(...) static_cast<void>(0)
//!===========================================================!//
//!  dP     dP                          dP                    !//
//!  88     88                          88                    !//
//!  88aaaaa88a .d8888b. .d8888b. .d888b88 .d8888b. 88d888b.  !//
//!  88     88  88ooood8 88'  '88 88'  '88 88ooood8 88'  '88  !//
//!  88     88  88.  ... 88.  .88 88.  .88 88.  ... 88        !//
//!  dP     dP  '88888P' '88888P8 '88888P8 '88888P' dP        !//
//!===========================================================!//
template <typename T>
T read()
{
    T v;
    return std::cin >> v, v;
}
template <typename T>
std::vector<T> readVec(const std::size_t l)
{
    std::vector<T> v(l);
    for (auto& e : v) { std::cin >> e; }
    return v;
}
using ld = long double;
using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
constexpr unsigned int MOD = 1000000007;
template <typename T>
constexpr T INF = std::numeric_limits<T>::max() / 4;
template <typename F>
constexpr F PI = static_cast<F>(3.1415926535897932385);
std::mt19937 mt{std::random_device{}()};
template <typename T>
bool chmin(T& a, const T& b) { return (a > b ? a = b, true : false); }
template <typename T>
bool chmax(T& a, const T& b) { return (a < b ? a = b, true : false); }
template <typename T>
std::vector<T> Vec(const std::size_t n, T v) { return std::vector<T>(n, v); }
template <class... Args>
auto Vec(const std::size_t n, Args... args) { return std::vector<decltype(Vec(args...))>(n, Vec(args...)); }
template <typename T>
constexpr T popCount(const T u)
{
#ifdef __has_builtin
    return u == 0 ? T(0) : (T)__builtin_popcountll(u);
#else
    unsigned long long v = static_cast<unsigned long long>(u);
    return v = (v & 0x5555555555555555ULL) + (v >> 1 & 0x5555555555555555ULL), v = (v & 0x3333333333333333ULL) + (v >> 2 & 0x3333333333333333ULL), v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL, static_cast<T>(v * 0x0101010101010101ULL >> 56 & 0x7f);
#endif
}
template <typename T>
constexpr T log2p1(const T u)
{
#ifdef __has_builtin
    return u == 0 ? T(0) : T(64 - __builtin_clzll(u));
#else
    unsigned long long v = static_cast<unsigned long long>(u);
    return v = static_cast<unsigned long long>(v), v |= (v >> 1), v |= (v >> 2), v |= (v >> 4), v |= (v >> 8), v |= (v >> 16), v |= (v >> 32), popCount(v);
#endif
}
template <typename T>
constexpr T clog(const T v) { return v == 0 ? T(0) : log2p1(v - 1); }
template <typename T>
constexpr T msbp1(const T v) { return log2p1(v); }
template <typename T>
constexpr T lsbp1(const T v)
{
#ifdef __has_builtin
    return __builtin_ffsll(v);
#else
    return v == 0 ? T(0) : popCount((v & (-v)) - T(1)) + T(1);
#endif
}
template <typename T>
constexpr bool ispow2(const T v) { return popCount(v) == 1; }
template <typename T>
constexpr T ceil2(const T v) { return v == 0 ? T(1) : T(1) << log2p1(v - 1); }
template <typename T>
constexpr T floor2(const T v) { return v == 0 ? T(0) : T(1) << (log2p1(v) - 1); }
//!===============================================================!//
//!   88888888b            dP       .88888.   a88888b. 888888ba   !//
//!   88                   88      d8'   '88 d8'   '88 88    '8b  !//
//!  a88aaaa    dP.  .dP d8888P    88        88        88     88  !//
//!   88         '8bd8'    88      88   YP88 88        88     88  !//
//!   88         .d88b.    88      Y8.   .88 Y8.   .88 88    .8P  !//
//!   88888888P dP'  'dP   dP       '88888'   Y88888P' 8888888P   !//
//!===============================================================!//
template <typename T>
constexpr std::pair<T, T> extgcd(const T a, const T b)
{
    if (b == 0) { return std::pair<T, T>{1, 0}; }
    const auto p = extgcd(b, a % b);
    return {p.second, p.first - p.second * (a / b)};
}
template <typename T>
constexpr T inverse(const T a, const T mod) { return (mod + extgcd((mod + a % mod) % mod, mod).first % mod) % mod; }
//!========================================================!//
//!  8888ba.88ba                 dP    dP            dP    !//
//!  88  '8b  '8b                88    88            88    !//
//!  88   88   88 .d8888b. .d888b88    88 88d888b. d8888P  !//
//!  88   88   88 88'  '88 88'  '88    88 88'  '88   88    !//
//!  88   88   88 88.  .88 88.  .88    88 88    88   88    !//
//!  dP   dP   dP '88888P' '88888P8    dP dP    dP   dP    !//
//!========================================================!//
template <uint mod>
class ModInt
{
private:
    uint v;
    static uint norm(const uint& x) { return x < mod ? x : x - mod; }
    static ModInt make(const uint& x)
    {
        ModInt m;
        return m.v = x, m;
    }
    static ModInt power(ModInt x, ll n)
    {
        ModInt ans = 1;
        for (; n; n >>= 1, x *= x) {
            if (n & 1) { ans *= x; }
        }
        return ans;
    }
    static ModInt inv(const ModInt& x) { return ModInt{inverse(static_cast<ll>(x.v), static_cast<ll>(mod))}; }

public:
    ModInt() : v{0} {}
    ModInt(const ll val) : v{norm(uint(val % static_cast<ll>(mod) + static_cast<ll>(mod)))} {}
    ModInt(const ModInt& n) : v{n()} {}
    explicit operator bool() const { return v != 0; }
    bool operator!() const { return not static_cast<bool>(*this); }
    ModInt& operator=(const ModInt& m) { return v = m(), (*this); }
    ModInt& operator=(const ll val) { return v = norm(uint(val % static_cast<ll>(mod) + static_cast<ll>(mod))), (*this); }
    friend ModInt operator+(const ModInt& m) { return m; }
    friend ModInt operator-(const ModInt& m) { return make(norm(mod - m.v)); }
    friend ModInt operator+(const ModInt& m1, const ModInt& m2) { return make(norm(m1.v + m2.v)); }
    friend ModInt operator-(const ModInt& m1, const ModInt& m2) { return make(norm(m1.v + mod - m2.v)); }
    friend ModInt operator*(const ModInt& m1, const ModInt& m2) { return make(static_cast<uint>(static_cast<ll>(m1.v) * static_cast<ll>(m2.v) % static_cast<ll>(mod))); }
    friend ModInt operator/(const ModInt& m1, const ModInt& m2) { return m1 * inv(m2.v); }
    friend ModInt operator+(const ModInt& m, const ll val) { return ModInt{static_cast<ll>(m.v) + val}; }
    friend ModInt operator-(const ModInt& m, const ll val) { return ModInt{static_cast<ll>(m.v) - val}; }
    friend ModInt operator*(const ModInt& m, const ll val) { return ModInt{static_cast<ll>(m.v) * (val % static_cast<ll>(mod))}; }
    friend ModInt operator/(const ModInt& m, const ll val) { return ModInt{static_cast<ll>(m.v) * inv(val)}; }
    friend ModInt operator+(const ll val, const ModInt& m) { return ModInt{static_cast<ll>(m.v) + val}; }
    friend ModInt operator-(const ll val, const ModInt& m) { return ModInt{-static_cast<ll>(m.v) + val}; }
    friend ModInt operator*(const ll val, const ModInt& m) { return ModInt{static_cast<ll>(m.v) * (val % static_cast<ll>(mod))}; }
    friend ModInt operator/(const ll val, const ModInt& m) { return ModInt{val * inv(static_cast<ll>(m.v))}; }
    friend ModInt& operator+=(ModInt& m1, const ModInt& m2) { return m1 = m1 + m2; }
    friend ModInt& operator-=(ModInt& m1, const ModInt& m2) { return m1 = m1 - m2; }
    friend ModInt& operator*=(ModInt& m1, const ModInt& m2) { return m1 = m1 * m2; }
    friend ModInt& operator/=(ModInt& m1, const ModInt& m2) { return m1 = m1 / m2; }
    friend ModInt& operator+=(ModInt& m, const ll val) { return m = m + val; }
    friend ModInt& operator-=(ModInt& m, const ll val) { return m = m - val; }
    friend ModInt& operator*=(ModInt& m, const ll val) { return m = m * val; }
    friend ModInt& operator/=(ModInt& m, const ll val) { return m = m / val; }
    friend ModInt operator^(const ModInt& m, const ll n) { return power(m.v, n); }
    friend ModInt& operator^=(ModInt& m, const ll n) { return m = m ^ n; }
    friend bool operator==(const ModInt& m1, const ModInt& m2) { return m1.v == m2.v; }
    friend bool operator!=(const ModInt& m1, const ModInt& m2) { return not(m1 == m2); }
    friend bool operator==(const ModInt& m, const ll val) { return m.v == norm(static_cast<uint>(static_cast<ll>(mod) + val % static_cast<ll>(mod))); }
    friend bool operator!=(const ModInt& m, const ll val) { return not(m == val); }
    friend bool operator==(const ll val, const ModInt& m) { return m.v == norm(static_cast<uint>(static_cast<ll>(mod) + val % static_cast<ll>(mod))); }
    friend bool operator!=(const ll val, const ModInt& m) { return not(m == val); }
    friend std::istream& operator>>(std::istream& is, ModInt& m)
    {
        uint v;
        return is >> v, m = v, is;
    }
    friend std::ostream& operator<<(std::ostream& os, const ModInt& m) { return os << m(); }
    static std::vector<ModInt> invVec(const std::size_t N)
    {
        std::vector<ModInt> ans(N + 1, 1);
        for (std::size_t i = 2; i <= N; i++) { ans[i] = -ans[mod % i] * (mod / i); }
        return ans;
    }
    uint operator()() const { return v; }
};
//!===============================!//
//!  888888ba  d888888P d888888P  !//
//!  88    '8b    88       88     !//
//!  88     88    88       88     !//
//!  88     88    88       88     !//
//!  88     88    88       88     !//
//!  dP     dP    dP       dP     !//
//!===============================!//
template <uint mod = 924844033, uint root = 5>
class NTT
{
private:
    static constexpr std::size_t L = 30;

public:
    NTT() = delete;
    static void ntt(std::vector<ModInt<mod>>& a, const std::size_t lg, const bool rev)
    {
        const std::size_t N = a.size();
        assert(1UL << lg == N);
        static std::vector<ModInt<mod>> R[L];
        if (R[lg].empty()) {
            R[lg].reserve(N), R[lg].resize(N, ModInt<mod>(1));
            const ModInt<mod> r = ModInt<mod>(root) ^ ((mod - 1) / N);
            for (std::size_t i = 1; i < N; i++) { R[lg][i] = R[lg][i - 1] * r; }
        }
        std::vector<ModInt<mod>> tmp(N);
        for (std::size_t w = (N >> 1); w > 0; w >>= 1) {
            for (std::size_t y = 0; y < (N >> 1); y += w) {
                const ModInt<mod> r = rev ? R[lg][y == 0 ? 0 : N - y] : R[lg][y];
                for (std::size_t x = 0; x < w; x++) {
                    const auto u = a[y << 1 | x], v = a[y << 1 | x | w]() * r;
                    tmp[y | x] = u + v, tmp[y | x | (N >> 1)] = u - v;
                }
            }
            std::swap(tmp, a);
        }
        if (rev) {
            for (std::size_t i = 0; i < N; i++) { a[i] /= ModInt<mod>(N); }
        }
    }
    static std::vector<ModInt<mod>> convolute(const std::vector<ModInt<mod>>& a, const std::vector<ModInt<mod>>& b)
    {
        const std::size_t need = a.size() + b.size() - 1, lg = clog(need), N = 1UL << lg;
        std::vector<ModInt<mod>> A(N, 0), B(N, 0);
        for (std::size_t i = 0; i < a.size(); i++) { A[i] = a[i](); }
        for (std::size_t i = 0; i < b.size(); i++) { B[i] = b[i](); }
        ntt(A, lg, false), ntt(B, lg, false);
        for (std::size_t i = 0; i < N; i++) { A[i] *= B[i]; }
        ntt(A, lg, true);
        std::vector<ModInt<mod>> ans(need);
        for (std::size_t i = 0; i < need; i++) { ans[i] = int(A[i]()); }
        return ans;
    }
};
//!=====================================!//
//!  8888ba.88ba           oo           !//
//!  88  '8b  '8b                       !//
//!  88   88   88 .d8888b. dP 88d888b.  !//
//!  88   88   88 88'  '88 88 88'  '88  !//
//!  88   88   88 88.  .88 88 88    88  !//
//!  dP   dP   dP '88888P8 dP dP    dP  !//
//!=====================================!//
int main()
{
    constexpr uint MOD = 998244353, ROOT = 5;
    using mint = ModInt<MOD>;
    const mint I3 = mint(1) / 3;
    const auto S = read<std::string>();
    const int N = S.size();
    mint T = 1;
    std::vector<mint> U(N), M(N), G(N);
    for (int i = 0; i < N; i++) {
        if (S[i] == 'U') {
            U[i] = 1;
        } else if (S[i] == 'M') {
            M[i] = 1;
        } else if (S[i] == 'G') {
            G[i] = 1;
        } else {
            T *= 3, U[i] = M[i] = G[i] = I3;
        }
    }
    std::vector<mint> UG(2 * N, 0);
    auto dfs = [&](auto&& self, const int l, const int r) -> void {
        const int m = (l + r) / 2;
        auto u = std::vector<mint>(U.begin() + l, U.begin() + m);
        auto g = std::vector<mint>(G.begin() + m, G.begin() + r);
        if (r - m <= 0 or m - l <= 0) { return; }
        const auto conv = NTT<MOD, ROOT>::convolute(u, g);
        for (int i = 0; i < conv.size(); i++) { UG[i + l + m] += conv[i]; }
        self(self, l, m), self(self, m, r);
    };
    dfs(dfs, 0, N);
    mint ans = 0;
    for (int i = 0; i < N; i++) { ans += M[i] * UG[2 * i]; }
    std::cout << ans * T << std::endl;
    return 0;
}
accuracy: 1
time_ms: 520
memory_kb: 13200
final_rank: 5

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < n; i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pi;
typedef pair<pi, pi> pp;
typedef pair<ll, ll> pl;
const double EPS = 1e-9;
const ll MOD = 998244353;
const int inf = 1 << 30;
const ll linf = 1LL << 60;

#define PI 3.141592653589793238462643383279 
typedef pair<double, double> com;
struct FFT{ //PIをdefineしておく, complex<double> com　をtypedefしておく
    int n;
    vector<com> a, b;
    vector<com> f[2];
    void init(vector<int>& p, vector<int>& q, int x){
        n = 1;
        while(n < x) n *= 2;
        a.resize(n, com(0,0));
        b.resize(n, com(0,0));
        rep(i,2) f[i].resize(n, com(0,0));
        //rep(i,n) a.push_back(com(0,0));
        //rep(i,n) b.push_back(com(0,0));
        //rep(i,2) rep(j,n) f[i].push_back(com(0,0));
        rep(i,p.size()) a[i] = com(p[i],0);
        rep(i,q.size()) b[i] = com(q[i],0);
    }

    inline com com_add (com a, com b) {
        return com(a.first+b.first, a.second+b.second);
    }

    inline com com_mul (com a, com b) {
        return com(a.first*b.first-a.second*b.second, a.first*b.second+a.second*b.first);
    }
    
    vector<com> dft(vector<com>& v, bool rev){
        int x = n, u = 0;
        f[0] = v;
        int ho = 0, ge = 1;
        for(int i = 2; i <= n; i <<= 1){
            u++; x >>= 1;
            com zeta;
            if(!rev) zeta = com(cos(2*PI/i),sin(2*PI/i));
            else zeta = com(cos(2*PI/i),-sin(2*PI/i));
            com pz;
            rep(j,x){
                pz = com(1,0);
                rep(k,i){
                    if(k>=i/2) f[ge][j*i+k] = com_add(f[ho][j*(i/2)+k-i/2],com_mul(pz,f[ho][j*(i/2)+n/2+k-i/2]));
                    else f[ge][j*i+k] = com_add(f[ho][j*(i/2)+k],com_mul(pz,f[ho][j*(i/2)+n/2+k]));
                    pz = com_mul(pz, zeta);
                }
            }
            swap(ho,ge);
        }
        return f[ho];
    }
    
    vector<com> multiply(vector<int>& p, vector<int>& q, int x){ //ｘは要素数の合計
        a.clear(); b.clear(); f[0].clear(); f[1].clear();
        init(p,q,x);
        a = dft(a,0);
        b = dft(b,0);
        rep(i,n) a[i] = com_mul(a[i],b[i]);
        a = dft(a,1);
        rep(i,n) a[i] = com(a[i].first/n, a[i].second/n);
        return a;
    }
};

string s;
ll cnt = 0;
vector<int> U, G;
ll p3[200001];
ll ans;
ll R3;
FFT fft;

void solve (int st, int en) {
    if (en-st <= 2) return;
    int mid = (st + en) / 2;
    vector<int> u, g;
    for (int i = st; i < mid; i++) u.push_back(U[i]);
    for (int i = mid; i < en; i++) g.push_back(G[i]);
    vector<com> rec = fft.multiply(u, g, en-st);
    rep(i,rec.size()) {
        ll val = ll(round(rec[i].first));
        if ((st+mid+i)%2 == 0) {
            if (s[(st+mid+i)/2] == 'M') ans = (ans + val*3) % MOD;
            if (s[(st+mid+i)/2] == '?') ans = (ans + val) % MOD;
        }
    }
    solve(st, mid); solve(mid, en);
}

ll mod_pow (ll x, ll y) {
    ll ret = 1;
    while (y) {
        if (y&1) ret = ret * x % MOD;
        x = x * x % MOD;
        y /= 2;
    }
    return ret;
}

int main() {
    cin >> s;
    R3 = mod_pow(3, MOD-2);
    U.resize(s.size()); G.resize(s.size());
    rep(i,s.size()) {
        if (s[i] == 'U') U[i] = 3;
        if (s[i] == 'G') G[i] = 3;
        if (s[i] == '?') { U[i] = 1; G[i] = 1; }
    }
    solve(0, s.size());
    ans = ans * mod_pow(27, MOD-2) % MOD;
    rep(i,s.size()) {
        if (s[i] == '?') ans = ans * 3 % MOD;
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 730
memory_kb: 31324
final_rank: 8

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < n; i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pi;
typedef pair<pi, pi> pp;
typedef pair<ll, ll> pl;
const double EPS = 1e-9;
const ll MOD = 998244353;
const int inf = 1 << 30;
const ll linf = 1LL << 60;

#define PI 3.141592653589793238462643383279 
typedef pair<double, double> com;
struct FFT{ //PIをdefineしておく, complex<double> com　をtypedefしておく
    int n;
    vector<com> a, b;
    vector<com> f[2];
    void init(vector<int>& p, vector<int>& q, int x){
        n = 1;
        while(n < x) n *= 2;
        a.resize(n, com(0,0));
        b.resize(n, com(0,0));
        rep(i,2) f[i].resize(n, com(0,0));
        //rep(i,n) a.push_back(com(0,0));
        //rep(i,n) b.push_back(com(0,0));
        //rep(i,2) rep(j,n) f[i].push_back(com(0,0));
        rep(i,p.size()) a[i] = com(p[i],0);
        rep(i,q.size()) b[i] = com(q[i],0);
    }

    inline com com_add (com a, com b) {
        return com(a.first+b.first, a.second+b.second);
    }

    inline com com_mul (com a, com b) {
        return com(a.first*b.first-a.second*b.second, a.first*b.second+a.second*b.first);
    }
    
    vector<com> dft(vector<com>& v, bool rev){
        int x = n, u = 0;
        f[0] = v;
        int ho = 0, ge = 1;
        for(int i = 2; i <= n; i <<= 1){
            u++; x >>= 1;
            com zeta;
            if(!rev) zeta = com(cos(2*PI/i),sin(2*PI/i));
            else zeta = com(cos(2*PI/i),-sin(2*PI/i));
            com pz;
            rep(j,x){
                pz = com(1,0);
                rep(k,i){
                    if(k>=i/2) f[ge][j*i+k] = com_add(f[ho][j*(i/2)+k-i/2],com_mul(pz,f[ho][j*(i/2)+n/2+k-i/2]));
                    else f[ge][j*i+k] = com_add(f[ho][j*(i/2)+k],com_mul(pz,f[ho][j*(i/2)+n/2+k]));
                    pz = com_mul(pz, zeta);
                }
            }
            swap(ho,ge);
        }
        return f[ho];
    }
    
    vector<com> multiply(vector<int>& p, vector<int>& q, int x){ //ｘは要素数の合計
        a.clear(); b.clear(); f[0].clear(); f[1].clear();
        init(p,q,x);
        a = dft(a,0);
        b = dft(b,0);
        rep(i,n) a[i] = com_mul(a[i],b[i]);
        a = dft(a,1);
        rep(i,n) a[i] = com(a[i].first/n, a[i].second/n);
        return a;
    }
};

string s;
ll cnt = 0;
vector<int> U, G;
ll p3[200001];
ll ans;
ll R3;
FFT fft;

void solve (int st, int en) {
    if (en-st <= 1) return;
    int mid = (st + en) / 2;
    vector<int> u, g;
    for (int i = st; i < mid; i++) u.push_back(U[i]);
    for (int i = mid; i < en; i++) g.push_back(G[i]);
    vector<com> rec = fft.multiply(u, g, en-st);
    rep(i,rec.size()) {
        ll val = ll(round(rec[i].first));
        if ((st+mid+i)%2 == 0) {
            if (s[(st+mid+i)/2] == 'M') ans = (ans + val*3) % MOD;
            if (s[(st+mid+i)/2] == '?') ans = (ans + val) % MOD;
        }
    }
    solve(st, mid); solve(mid, en);
}

ll mod_pow (ll x, ll y) {
    ll ret = 1;
    while (y) {
        if (y&1) ret = ret * x % MOD;
        x = x * x % MOD;
        y /= 2;
    }
    return ret;
}

int main() {
    cin >> s;
    R3 = mod_pow(3, MOD-2);
    U.resize(s.size()); G.resize(s.size());
    rep(i,s.size()) {
        if (s[i] == 'U') U[i] = 3;
        if (s[i] == 'G') G[i] = 3;
        if (s[i] == '?') { U[i] = 1; G[i] = 1; }
    }
    solve(0, s.size());
    ans = ans * mod_pow(27, MOD-2) % MOD;
    rep(i,s.size()) {
        if (s[i] == '?') ans = ans * 3 % MOD;
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 740
memory_kb: 31292
final_rank: 9

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < n; i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pi;
typedef pair<pi, pi> pp;
typedef pair<ll, ll> pl;
const double EPS = 1e-9;
const ll MOD = 998244353;
const int inf = 1 << 30;
const ll linf = 1LL << 60;

#define PI 3.141592653589793238462643383279 
typedef complex<double> com;
struct FFT{ //PIをdefineしておく, complex<double> com　をtypedefしておく
    int n;
    vector<com> a, b;
    vector<com> f[2];
    void init(vector<int>& p, vector<int>& q, int x){
        n = 1;
        while(n < x) n *= 2;
        a.resize(n, com(0,0));
        b.resize(n, com(0,0));
        rep(i,2) f[i].resize(n, com(0,0));
        //rep(i,n) a.push_back(com(0,0));
        //rep(i,n) b.push_back(com(0,0));
        //rep(i,2) rep(j,n) f[i].push_back(com(0,0));
        rep(i,p.size()) a[i] = com(p[i],0);
        rep(i,q.size()) b[i] = com(q[i],0);
    }
    
    vector<com> dft(vector<com>& v, bool rev){
        int x = n, u = 0;
        f[0] = v;
        int ho = 0, ge = 1;
        for(int i = 2; i <= n; i <<= 1){
            u++; x >>= 1;
            com zeta;
            if(!rev) zeta = com(cos(2*PI/i),sin(2*PI/i));
            else zeta = com(cos(2*PI/i),-sin(2*PI/i));
            com pz;
            rep(j,x){
                pz = com(1,0);
                rep(k,i){
                    if(k>=i/2) f[ge][j*i+k] = f[ho][j*(i/2)+k-i/2]+pz*f[ho][j*(i/2)+n/2+k-i/2];
                    else f[ge][j*i+k] = f[ho][j*(i/2)+k]+pz*f[ho][j*(i/2)+n/2+k];
                    pz *= zeta;
                }
            }
            swap(ho,ge);
        }
        return f[ho];
    }
    
    vector<com> multiply(vector<int>& p, vector<int>& q, int x){ //ｘは要素数の合計
        a.clear(); b.clear(); f[0].clear(); f[1].clear();
        init(p,q,x);
        a = dft(a,0);
        b = dft(b,0);
        rep(i,n) a[i] = a[i]*b[i];
        a = dft(a,1);
        rep(i,n) a[i] /= n;
        return a;
    }
};

string s;
ll cnt = 0;
vector<int> U, G;
ll p3[200001];
ll ans;
ll R3;
FFT fft;

void solve (int st, int en) {
    if (en-st <= 1) return;
    int mid = (st + en) / 2;
    vector<int> u, g;
    for (int i = st; i < mid; i++) u.push_back(U[i]);
    for (int i = mid; i < en; i++) g.push_back(G[i]);
    vector<com> rec = fft.multiply(u, g, en-st);
    rep(i,rec.size()) {
        ll val = ll(round(rec[i].real()));
        if ((st+mid+i)%2 == 0) {
            if (s[(st+mid+i)/2] == 'M') ans = (ans + val*3) % MOD;
            if (s[(st+mid+i)/2] == '?') ans = (ans + val) % MOD;
        }
    }
    solve(st, mid); solve(mid, en);
}

ll mod_pow (ll x, ll y) {
    ll ret = 1;
    while (y) {
        if (y&1) ret = ret * x % MOD;
        x = x * x % MOD;
        y /= 2;
    }
    return ret;
}

int main() {
    cin >> s;
    R3 = mod_pow(3, MOD-2);
    U.resize(s.size()); G.resize(s.size());
    rep(i,s.size()) {
        if (s[i] == 'U') U[i] = 3;
        if (s[i] == 'G') G[i] = 3;
        if (s[i] == '?') { U[i] = 1; G[i] = 1; }
    }
    solve(0, s.size());
    ans = ans * mod_pow(27, MOD-2) % MOD;
    rep(i,s.size()) {
        if (s[i] == '?') ans = ans * 3 % MOD;
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 1280
memory_kb: 31288
final_rank: 12

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < n; i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pi;
typedef pair<pi, pi> pp;
typedef pair<ll, ll> pl;
const double EPS = 1e-9;
const ll MOD = 998244353;
const int inf = 1 << 30;
const ll linf = 1LL << 60;

#define PI 3.141592653589793238462643383279 
typedef complex<double> com;
struct FFT{ //PIをdefineしておく, complex<double> com　をtypedefしておく
    int n;
    vector<com> a, b;
    vector<com> f[2];
    void init(vector<int> p, vector<int> q, int x){
        n = 1;
        while(n < x) n *= 2;
        a.resize(n, com(0,0));
        b.resize(n, com(0,0));
        rep(i,2) f[i].resize(n, com(0,0));
        //rep(i,n) a.push_back(com(0,0));
        //rep(i,n) b.push_back(com(0,0));
        //rep(i,2) rep(j,n) f[i].push_back(com(0,0));
        rep(i,p.size()) a[i] = com(p[i],0);
        rep(i,q.size()) b[i] = com(q[i],0);
    }
    
    vector<com> dft(vector<com> v, bool rev){
        int x = n, u = 0;
        f[0] = v;
        int ho = 0, ge = 1;
        for(int i = 2; i <= n; i <<= 1){
            u++; x >>= 1;
            com zeta;
            if(!rev) zeta = com(cos(2*PI/i),sin(2*PI/i));
            else zeta = com(cos(2*PI/i),-sin(2*PI/i));
            com pz;
            rep(j,x){
                pz = com(1,0);
                rep(k,i){
                    if(k>=i/2) f[ge][j*i+k] = f[ho][j*(i/2)+k-i/2]+pz*f[ho][j*(i/2)+n/2+k-i/2];
                    else f[ge][j*i+k] = f[ho][j*(i/2)+k]+pz*f[ho][j*(i/2)+n/2+k];
                    pz *= zeta;
                }
            }
            swap(ho,ge);
        }
        return f[ho];
    }
    
    vector<com> multiply(vector<int> p, vector<int> q, int x){ //ｘは要素数の合計
        a.clear(); b.clear(); f[0].clear(); f[1].clear();
        init(p,q,x);
        a = dft(a,0);
        b = dft(b,0);
        rep(i,n) a[i] = a[i]*b[i];
        a = dft(a,1);
        rep(i,n) a[i] /= n;
        return a;
    }
};

string s;
ll cnt = 0;
vector<int> U, G;
ll p3[200001];
ll ans;
ll R3;
FFT fft;

void solve (int st, int en) {
    if (en-st <= 1) return;
    int mid = (st + en) / 2;
    vector<int> u, g;
    for (int i = st; i < mid; i++) u.push_back(U[i]);
    for (int i = mid; i < en; i++) g.push_back(G[i]);
    vector<com> rec = fft.multiply(u, g, en-st);
    rep(i,rec.size()) {
        ll val = ll(round(rec[i].real()));
        if ((st+mid+i)%2 == 0) {
            if (s[(st+mid+i)/2] == 'M') ans = (ans + val*3) % MOD;
            if (s[(st+mid+i)/2] == '?') ans = (ans + val) % MOD;
        }
    }
    solve(st, mid); solve(mid, en);
}

ll mod_pow (ll x, ll y) {
    ll ret = 1;
    while (y) {
        if (y&1) ret = ret * x % MOD;
        x = x * x % MOD;
        y /= 2;
    }
    return ret;
}

int main() {
    cin >> s;
    R3 = mod_pow(3, MOD-2);
    U.resize(s.size()); G.resize(s.size());
    rep(i,s.size()) {
        if (s[i] == 'U') U[i] = 3;
        if (s[i] == 'G') G[i] = 3;
        if (s[i] == '?') { U[i] = 1; G[i] = 1; }
    }
    solve(0, s.size());
    ans = ans * mod_pow(27, MOD-2) % MOD;
    rep(i,s.size()) {
        if (s[i] == '?') ans = ans * 3 % MOD;
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 1410
memory_kb: 31580
final_rank: 14

code_snippet: #include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <cmath>
#include <bitset>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <algorithm>
#include <complex>
#include <unordered_map>
#include <unordered_set>
#include <random>
#include <cassert>
#include <fstream>
#define popcount __builtin_popcount
using namespace std;
typedef long long int ll;
typedef pair<int, int> Pii;
 
#define FOR(i,n) for(int i = 0; i < (n); i++)
#define sz(c) ((int)(c).size())
#define ten(x) ((int)1e##x)
 
template<class T> T extgcd(T a, T b, T& x, T& y) { for (T u = y = 1, v = x = 0; a;) { T q = b / a; swap(x -= q * u, u); swap(y -= q * v, v); swap(b -= q * a, a); } return b; }
template<class T> T mod_inv(T a, T m) { T x, y; extgcd(a, m, x, y); return (m + x % m) % m; }
ll mod_pow(ll a, ll n, ll mod) { ll ret = 1; ll p = a % mod; while (n) { if (n & 1) ret = ret * p % mod; p = p * p % mod; n >>= 1; } return ret; }
 
template<int mod, int primitive_root>
class NTT {
public:
	int get_mod() const { return mod; }
	void _ntt(vector<ll>& a, int sign) {
		const int n = sz(a);
		assert((n ^ (n&-n)) == 0); //n = 2^k
 
		const int g = 5; //g is primitive root of mod
		int h = (int)mod_pow(g, (mod - 1) / n, mod); // h^n = 1
		if (sign == -1) h = (int)mod_inv(h, mod); //h = h^-1 % mod
 
		//bit reverse
		int i = 0;
		for (int j = 1; j < n - 1; ++j) {
			for (int k = n >> 1; k >(i ^= k); k >>= 1);
			if (j < i) swap(a[i], a[j]);
		}
 
		for (int m = 1; m < n; m *= 2) {
			const int m2 = 2 * m;
			const ll base = mod_pow(h, n / m2, mod);
			ll w = 1;
			FOR(x, m) {
				for (int s = x; s < n; s += m2) {
					ll u = a[s];
					ll d = a[s + m] * w % mod;
					a[s] = u + d;
					if (a[s] >= mod) a[s] -= mod;
					a[s + m] = u - d;
					if (a[s + m] < 0) a[s + m] += mod;
				}
				w = w * base % mod;
			}
		}
 
		for (auto& x : a) if (x < 0) x += mod;
	}
	void ntt(vector<ll>& input) {
		_ntt(input, 1);
	}
	void intt(vector<ll>& input) {
		_ntt(input, -1);
		const int n_inv = mod_inv(sz(input), mod);
		for (auto& x : input) x = x * n_inv % mod;
	}
 
	// 畳み込み演算を行う
	vector<ll> convolution(const vector<ll>& a, const vector<ll>& b){
		int ntt_size = 1;
		while (ntt_size < sz(a) + sz(b)) ntt_size *= 2;
 
		vector<ll> _a = a, _b = b;
		_a.resize(ntt_size); _b.resize(ntt_size);
 
		ntt(_a);
		ntt(_b);
 
		FOR(i, ntt_size){
			(_a[i] *= _b[i]) %= mod;
		}
 
		intt(_a);
		return _a;
	}
};
 
const ll MOD=998244353;
const ll inv3=332748118;
typedef NTT<MOD, 3> NTT_1;
NTT_1 ntt;
ll ans;
int n;
string s;
void solve(int l, int r){
    if(r-l<2) return;
    int m=(l+r)/2;
    vector<ll> x(m-l+1), y(r-m);
    for(int i=0; i<m-l+1; i++){
        if(s[l+i]=='U') x[i]=1;
        else if(s[l+i]=='?') x[i]=inv3;
    }
    for(int i=0; i<r-m; i++){
        if(s[m+1+i]=='G') y[i]=1;
        else if(s[m+1+i]=='?') y[i]=inv3;
    }
    vector<ll> z=ntt.convolution(x, y);
    z.resize(r-l);
    for(int i=l; i<=r; i++){
        if(2*i-m-l-1<0 || 2*i-m-l-1>=r-l) continue;
        if(s[i]=='M') (ans+=z[2*i-m-l-1])%=MOD;
        else if(s[i]=='?') (ans+=z[2*i-m-l-1]*inv3)%=MOD;
    }
    solve(l, m);
    solve(m+1, r);
}
int main()
{
    cin>>s;
    n=s.size();
    ll p=1;
    for(int i=0; i<n; i++) if(s[i]=='?') p=p*3%MOD;
    solve(0, n-1);
    ans=ans*p%MOD;
    cout<<ans<<endl;
    return 0;
}
accuracy: 1
time_ms: 810
memory_kb: 10424
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define FORR(i,a,b) for(int i=(int)(b)-1;i>=(int)(a);i--)

#define CHMIN(a,b) (a)=min((a),(b))
#define CHMAX(a,b) (a)=max((a),(b))

#define DEBUG(x) cout<<#x<<": "<<(x)<<endl

#define MOD 998244353

int n;
char s[252521];
ll tpow[252521];
ll fa[1<<19], fc[1<<19];
ll conv[1<<19];

#define THR 8

inline ll modadd(ll b, ll c){
	ll a = b+c;
	return a>=MOD ? a-MOD : a;
}
inline ll modadd(ll b, ll c, ll d){
	ll a = b+c;
	a = a>=MOD ? a-MOD : a;
	a = a+d;
	return a>=MOD ? a-MOD : a;
}

ll tmp[1<<19];
void k1(int n, ll *ret, ll *a, ll *b, ll *tmp);
void k2(int n, ll *ret, ll *a, ll *b, ll *tmp);
// HUPC2019Day2H向けチューニング
// 偶数しか参照しない性質で処理をサボる
// ref: @koba_procon
ll ain[1<<18], bin[1<<18];
void asym_comb_even(int n, ll *ret, ll *a, ll *b, ll *tmp){
	int m = n/2;
	REP(i,m)ain[i] = a[2*i];
	REP(i,m)bin[i] = b[2*i];
	k1(m, ret, ain, bin, tmp);
	REP(i,m)ain[i] = a[2*i+1];
	REP(i,m)bin[i] = b[2*i+1];
	k1(m, ret+n+1, ain, bin, tmp);
	REP(i,n)ret[i] = modadd(ret[i], ret[i+n]);
	fill(ret+n,ret+2*n,0ll);
	FORR(i,0,n)swap(ret[i], ret[2*i]);
}
void k1(int n, ll *ret, ll *a, ll *b, ll *tmp){
	if(n<=THR){
		REP(i,n)FOR(j,i+1,n)ret[i+j] = modadd(ret[i+j],a[i]*b[j]%MOD);
		return;
	}else{
		int m = n/2;
		fill(tmp,tmp+n,0);
		k2(m, tmp, a, b+m, tmp+n);
		k1(m, ret, a, b, tmp+n);
		k1(m, ret+n, a+m, b+m, tmp+n);
		REP(i,n)ret[i+m] = modadd(ret[i+m], tmp[i]);
		return;
	}
}
void k2(int n, ll *ret, ll *a, ll *b, ll *tmp){
	if(n<=THR){
		REP(i,n)REP(j,n)ret[i+j] = modadd(ret[i+j],a[i]*b[j]%MOD);
		return;
	}else{
		int m = n/2;
		REP(i,m)ret[i] = modadd(a[i], a[i+m]);
		REP(i,m)ret[i+m] = modadd(b[i], b[i+m]);
		fill(tmp,tmp+n,0);
		k2(m, tmp, ret, ret+m, tmp+n);
		fill(ret,ret+n,0);
		k2(m, ret, a, b, tmp+n);
		k2(m, ret+n, a+m, b+m, tmp+n);
		REP(i,n)tmp[i] = modadd(tmp[i],MOD-ret[i],MOD-ret[i+n]);
		REP(i,n)ret[i+m] = modadd(ret[i+m], tmp[i]);
		return;
	}
}

int main(){
	scanf("%s",s);
	n = strlen(s);
	REP(i,n){
		if(s[i]=='U'){
			s[i] = 'A';
		}else if(s[i]=='M'){
			s[i] = 'B';
		}else if(s[i]=='G'){
			s[i] = 'C';
		}
	}
	tpow[0] = 1;
	FOR(i,1,252521)tpow[i] = tpow[i-1]*3%MOD;
	ll iv3 = (MOD+1)/3;
	// O(N^2)
	int qcnt = count(s,s+n,'?');
	ll ans = 0;
	REP(i,n){
		if(s[i]=='A')fa[i] = 1;
		if(s[i]=='?')fa[i] = iv3;

		if(s[i]=='C')fc[i] = 1;
		if(s[i]=='?')fc[i] = iv3;
	}
	// sum_k (fa[i-k] * fc[i+k])
	// (fa * fc)[2i]
	// ntt oboete nai
	asym_comb_even(1<<18,conv,fa,fc,tmp);
	REP(i,n){
		if(s[i]=='B'){
			ll sum = conv[2*i];
			ans = (ans + sum * tpow[qcnt]) % MOD;
		}else if(s[i]=='?'){
			ll sum = conv[2*i];
			ans = (ans + sum * tpow[qcnt-1]) % MOD;
		}
	}
	printf("%lld\n",ans);
	return 0;
}
accuracy: 1
time_ms: 1690
memory_kb: 16692
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define FORR(i,a,b) for(int i=(int)(b)-1;i>=(int)(a);i--)

#define CHMIN(a,b) (a)=min((a),(b))
#define CHMAX(a,b) (a)=max((a),(b))

#define DEBUG(x) cout<<#x<<": "<<(x)<<endl

#define MOD 998244353

int n;
char s[252521];
ll tpow[252521];
ll fa[1<<19], fc[1<<19];
ll conv[1<<19];

#define THR 8

inline ll modadd(ll b, ll c){
	ll a = b+c;
	return a>=MOD ? a-MOD : a;
}
inline ll modadd(ll b, ll c, ll d){
	ll a = b+c;
	a = a>=MOD ? a-MOD : a;
	a = a+d;
	return a>=MOD ? a-MOD : a;
}

ll tmp[1<<19];
void k2(int n, ll *ret, ll *a, ll *b, ll *tmp);
void k1(int n, ll *ret, ll *a, ll *b, ll *tmp){
	if(n<=THR){
		REP(i,n)FOR(j,i+1,n)ret[i+j] = modadd(ret[i+j],a[i]*b[j]%MOD);
		return;
	}else{
		int m = n/2;
		fill(tmp,tmp+n,0);
		k2(m, tmp, a, b+m, tmp+n);
		k1(m, ret, a, b, tmp+n);
		k1(m, ret+n, a+m, b+m, tmp+n);
		for(int i=0; i<n; i+=2)ret[i+m] = modadd(ret[i+m], tmp[i]);
		return;
	}
}
void k2(int n, ll *ret, ll *a, ll *b, ll *tmp){
	if(n<=THR){
		REP(i,n)REP(j,n)ret[i+j] = modadd(ret[i+j],a[i]*b[j]%MOD);
		return;
	}else{
		int m = n/2;
		REP(i,m)ret[i] = modadd(a[i], a[i+m]);
		REP(i,m)ret[i+m] = modadd(b[i], b[i+m]);
		fill(tmp,tmp+n,0);
		k2(m, tmp, ret, ret+m, tmp+n);
		fill(ret,ret+n,0);
		k2(m, ret, a, b, tmp+n);
		k2(m, ret+n, a+m, b+m, tmp+n);
		for(int i=0; i<n; i+=2)tmp[i] = modadd(tmp[i],MOD-ret[i],MOD-ret[i+n]);
		for(int i=0; i<n; i+=2)ret[i+m] = modadd(ret[i+m], tmp[i]);
		return;
	}
}

int main(){
	scanf("%s",s);
	n = strlen(s);
	REP(i,n){
		if(s[i]=='U'){
			s[i] = 'A';
		}else if(s[i]=='M'){
			s[i] = 'B';
		}else if(s[i]=='G'){
			s[i] = 'C';
		}
	}
	tpow[0] = 1;
	FOR(i,1,200025)tpow[i] = tpow[i-1]*3%MOD;
	ll iv3 = (MOD+1)/3;
	// O(N^2)
	int qcnt = count(s,s+n,'?');
	ll ans = 0;
	REP(i,n){
		if(s[i]=='A')fa[i] = 1;
		if(s[i]=='?')fa[i] = iv3;

		if(s[i]=='C')fc[i] = 1;
		if(s[i]=='?')fc[i] = iv3;
	}
	// sum_k (fa[i-k] * fc[i+k])
	// (fa * fc)[2i]
	// ntt oboete nai
	k1(1<<18,conv,fa,fc,tmp);
	REP(i,n){
		if(s[i]=='B'){
			ll sum = conv[2*i];
			ans = (ans + sum * tpow[qcnt]) % MOD;
		}else if(s[i]=='?'){
			ll sum = conv[2*i];
			ans = (ans + sum * tpow[qcnt-1]) % MOD;
		}
	}
	printf("%lld\n",ans);
	return 0;
}
accuracy: 1
time_ms: 2480
memory_kb: 16284
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define FORR(i,a,b) for(int i=(int)(b)-1;i>=(int)(a);i--)

#define CHMIN(a,b) (a)=min((a),(b))
#define CHMAX(a,b) (a)=max((a),(b))

#define DEBUG(x) cout<<#x<<": "<<(x)<<endl

#define MOD 998244353

int n;
char s[252521];
ll tpow[252521];
ll fa[1<<19], fc[1<<19];
ll conv[1<<19];

#define THR 8

inline ll modadd(ll b, ll c){
	ll a = b+c;
	return a>=MOD ? a-MOD : a;
}
inline ll modadd(ll b, ll c, ll d){
	ll a = b+c;
	a = a>=MOD ? a-MOD : a;
	a = a+d;
	return a>=MOD ? a-MOD : a;
}

ll tmp[1<<19];
void k2(int n, ll *ret, ll *a, ll *b, ll *tmp);
void k1(int n, ll *ret, ll *a, ll *b, ll *tmp){
	if(n<=THR){
		REP(i,n)FOR(j,i+1,n)ret[i+j] = modadd(ret[i+j],a[i]*b[j]%MOD);
		return;
	}else{
		int m = n/2;
		fill(tmp,tmp+n,0);
		k2(m, tmp, a, b+m, tmp+n);
		k1(m, ret, a, b, tmp+n);
		k1(m, ret+n, a+m, b+m, tmp+n);
		REP(i,n)ret[i+m] = modadd(ret[i+m], tmp[i]);
		return;
	}
}
void k2(int n, ll *ret, ll *a, ll *b, ll *tmp){
	if(n<=THR){
		REP(i,n)REP(j,n)ret[i+j] = modadd(ret[i+j],a[i]*b[j]%MOD);
		return;
	}else{
		int m = n/2;
		REP(i,m)ret[i] = modadd(a[i], a[i+m]);
		REP(i,m)ret[i+m] = modadd(b[i], b[i+m]);
		fill(tmp,tmp+n,0);
		k2(m, tmp, ret, ret+m, tmp+n);
		fill(ret,ret+n,0);
		k2(m, ret, a, b, tmp+n);
		k2(m, ret+n, a+m, b+m, tmp+n);
		REP(i,n)tmp[i] = modadd(tmp[i],MOD-ret[i],MOD-ret[i+n]);
		REP(i,n)ret[i+m] = modadd(ret[i+m], tmp[i]);
		return;
	}
}

int main(){
	scanf("%s",s);
	n = strlen(s);
	REP(i,n){
		if(s[i]=='U'){
			s[i] = 'A';
		}else if(s[i]=='M'){
			s[i] = 'B';
		}else if(s[i]=='G'){
			s[i] = 'C';
		}
	}
	tpow[0] = 1;
	FOR(i,1,252521)tpow[i] = tpow[i-1]*3%MOD;
	ll iv3 = (MOD+1)/3;
	// O(N^2)
	int qcnt = count(s,s+n,'?');
	ll ans = 0;
	REP(i,n){
		if(s[i]=='A')fa[i] = 1;
		if(s[i]=='?')fa[i] = iv3;

		if(s[i]=='C')fc[i] = 1;
		if(s[i]=='?')fc[i] = iv3;
	}
	// sum_k (fa[i-k] * fc[i+k])
	// (fa * fc)[2i]
	// ntt oboete nai
	k1(1<<18,conv,fa,fc,tmp);
	REP(i,n){
		if(s[i]=='B'){
			ll sum = conv[2*i];
			ans = (ans + sum * tpow[qcnt]) % MOD;
		}else if(s[i]=='?'){
			ll sum = conv[2*i];
			ans = (ans + sum * tpow[qcnt-1]) % MOD;
		}
	}
	printf("%lld\n",ans);
	return 0;
}
accuracy: 1
time_ms: 2490
memory_kb: 16700
final_rank: 18