Problem:
Incredibly Cute Penguin Chicks
The
Incredibly Cute Penguin Chicks
love to eat worms. One day, their mother found a long string-shaped worm with a number of letters on it. She decided to cut this worm into pieces and feed the chicks.
The chicks somehow love
International Collegiate Programming Contest
and want to eat pieces with
ICPC-ish
character strings on them. Here, a string is ICPC-ish if the following conditions hold.
It consists of only C's, I's, and P's.
Two of these three characters appear the same number of times (possibly zero times) in the string and the remaining character appears strictly more times.
For example, ICPC and PPPPPP are ICPC-ish, but PIC, PIPCCC and PIPE are not.
You are given the string on the worm the mother found. The mother wants to provide one or more parts of the worm all with an ICPC-ish string, without wasting remains. Your task is to count the number of ways the worm can be prepared in such a manner.
Input
The input is a single line containing a character string $S$ consisting of only C's, I's, and P's, which is on the string-shaped worm the mother penguin found. The length of $S$ is between $1$ and $10^6$, inclusive.
Output
Print in a line the number of ways to represent the string S as a concatenation of one or more
ICPC-ish strings modulo a prime number $998 244 353 = 2^{23} \times 7 \times 17 + 1$.
Sample Input 1
ICPC
Sample Output 1
2
Sample Input 2
CCCIIIPPP
Sample Output 2
69
Sample Input 3
PICCICCIPPI
Sample Output 3
24
In the first sample, the string "ICPC" can be represented in the following two ways.
A single ICPC-ish string, "ICPC".
Concatenation of four ICPC-ish strings, "I", "C", "P", and "C".

Submitted solutions:

code_snippet: // #define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1LL << 60;
#define rep(i, a) for(ll i = 0; i < (a); i++)
#define all(a) begin(a), end(a)
#define sz(a) (a).size()
bool chmin(auto& a, auto b) { return a > b ? a = b, 1 : 0; }
bool chmax(auto& a, auto b) { return a < b ? a = b, 1 : 0; }
#define out(a) cout << (a) << endl
using vll = vector<ll>;
using vvll = vector<vll>;
using pll = pair<ll, ll>;
using vpll = vector<pll>;
using vvpll = vector<vpll>;

const ll mod = 998244353;
struct mm{
    ll x;
    mm(ll x_ = 0) : x(x_ % mod)
    {
        if(x < 0) x += mod;
    }
    friend mm operator+(mm a, mm b) { return a.x + b.x; }
    friend mm operator-(mm a, mm b) { return a.x - b.x; }
    friend mm operator*(mm a, mm b) { return a.x * b.x; }
    friend mm operator/(mm& a, mm b) { return a.x * b.inv(); }
    friend mm operator+=(mm& a, mm b) { return a = a.x + b.x; }
    friend mm operator-=(mm& a, mm b) { return a = a.x - b.x; }
    friend mm operator*=(mm& a, mm b) { return a = a.x * b.x; }
    friend mm operator/=(mm& a, mm b) { return a = a.x * b.inv(); }
    mm inv() const { return pow(mod - 2); }
    mm pow(ll b) const {
        mm a = *this, c = 1;
        while(b){
            if(b & 1) c *= a;
            a *= a;
            b >>= 1;
        }
        return c;
    }
};

struct BIT {
    vector<mm> a;
    BIT() = default;
    BIT(ll n) : a(n + 1) {}
    void add(ll i, mm x)
    {
        i++;
        while(i < sz(a))
        {
            a[i] += x;
            i += i & -i;
        }
    }
    mm sum(ll r)
    {
        mm s = 0;
        while(r)
        {
            s += a[r];
            r -= r & -r;
        }
        return s;
    }

    mm sum(ll l, ll r)
    {
        return sum(r) - sum(l);
    }
};

int main()
{
    string S; cin >> S;
    ll N = S.size();
    vpll pos(N + 1, {0, 0});
    ll bx = 0, by = 0;
    unordered_map<ll, vpll> H, W, D;
    H[0].emplace_back(0, 0);
    W[0].emplace_back(0, 0);
    D[0].emplace_back(0, 0);
    rep(i, N)
    {
        if(S[i] == 'I')
        {
            bx++;
        }
        else if(S[i] == 'C')
        {
            by++;
        }
        else
        {
            bx--;
            by--;
        }
        pos[i + 1] = {bx, by};
        H[bx].emplace_back(bx, by);
        W[by].emplace_back(bx, by);
        D[bx - by].emplace_back(bx, by);
    }
    // for(auto [x, y] : pos) cout << x << " " << y << endl;
    map<pll, ll> iH, iW, iD;
    unordered_map<ll, BIT> HB, WB, DB;
    for(auto &[key, vec] : H)
    {
        sort(all(vec));
        vec.erase(unique(all(vec)), vec.end());
        ll n = vec.size();
        HB[key] = BIT(n);
        rep(i, n)
        {
            iH[vec[i]] = i;
        }
    }
    for(auto &[key, vec] : W)
    {
        sort(all(vec));
        vec.erase(unique(all(vec)), vec.end());
        ll n = vec.size();
        WB[key] = BIT(n);
        rep(i, n)
        {
            iW[vec[i]] = i;
        }
    }
    for(auto &[key, vec] : D)
    {
        sort(all(vec));
        vec.erase(unique(all(vec)), vec.end());
        ll n = vec.size();
        DB[key] = BIT(n);
        rep(i, n)
        {
            iD[vec[i]] = i;
        }
    }
    HB[0].add(iH[{0, 0}], 1);
    WB[0].add(iW[{0, 0}], 1);
    DB[0].add(iD[{0, 0}], 1);
    // HB[pos[1].first].add(iH[{pos[1]}], 1);
    // WB[pos[1].second].add(iW[{pos[1]}], 1);
    // DB[pos[1].first - pos[1].second].add(iD[{pos[1]}], 1);
    mm ans = 0;
    for(ll i = 1; i <= N; i++)
    {
        pll p = pos[i];
        mm ad = 0;
        ad += HB[p.first].sum(0, iH[p]);
        ad += WB[p.second].sum(0, iW[p]);
        ad += DB[p.first - p.second].sum(iD[p] + 1, DB[p.first - p.second].a.size() - 1);
        HB[p.first].add(iH[p], ad);
        WB[p.second].add(iW[p], ad);
        DB[p.first - p.second].add(iD[p], ad);
        ans = ad;
    }
    cout << ans.x << endl;
}
accuracy: 1
time_ms: 1610
memory_kb: 588672
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define vi vector<int>
#define vl vector<ll>
#define vii vector<pair<int,int>>
#define vll vector<pair<ll,ll>>
#define vvi vector<vector<int>>
#define vvl vector<vector<ll>>
#define vvii vector<vector<pair<int,int>>>
#define vvll vector<vector<pair<ll,ll>>>
#define vst vector<string>
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define mkunique(x) sort(all(x));(x).erase(unique(all(x)),(x).end())
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=300005,INF=15<<26;

//modint+畳み込み+逆元テーブル

// from: https://gist.github.com/yosupo06/ddd51afb727600fd95d9d8ad6c3c80c9
// (based on AtCoder STL)

#include <algorithm>
#include <array>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

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 atcoder



#include <utility>

namespace atcoder {

namespace internal {

constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

struct barrett {
    unsigned int _m;
    unsigned long long im;
    
    barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}
    
    unsigned int umod() const { return _m; }
    
    unsigned int mul(unsigned int a, unsigned int b) const {
        
        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;
    }
};

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;
}

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;
    for (long long a : {2, 7, 61}) {
        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);

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};
    
    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
        
        
        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

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 atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

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 atcoder

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

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 atcoder

#include <cassert>
#include <type_traits>
#include <vector>

namespace atcoder {

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--) {
            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--) {
            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;
}

}  // namespace atcoder

using mint=atcoder::modint998244353;

vector<mint> inv,fac,finv;

void make(){
    
    inv.resize(MAX);
    fac.resize(MAX);
    finv.resize(MAX);
    fac[0]=fac[1]=1;
    finv[0]=finv[1]=1;
    inv[1]=1;
    
    for(int i=2;i<MAX;i++){
        inv[i]=-inv[mod%i]*(mod/i);
        fac[i]=fac[i-1]*i;
        finv[i]=finv[i-1]*inv[i];
    }
}

mint comb(ll a,ll b){
    if(a<b) return 0;
    return fac[a]*finv[b]*finv[a-b];
}

mint perm(ll a,ll b){
    if(a<b) return 0;
    return fac[a]*finv[a-b];
}

//SRM用 BIT

struct BIT{
    vector<mint> bit;
    int N;
    
    void init(int n_){
        N=n_;
        n_*=2;
        for(int i=30;i>=0;i--){
            if(n_&(1<<i)){
                n_=1<<i;
                n_++;
                break;
            }
        }
        bit.assign(n_,0);
    }
    
    mint sum(int i){
        mint s=0;
        while(i>0){
            s+=bit[i];
            i-=i&-i;
        }
        return s;
    }
    
    mint sum(int l,int r){
        if(l>=r) return 0;
        return sum(r)-sum(l);
    }
    //[l,r)
    
    void add(int i,mint x){
        i++;
        while(i<=N){
            bit[i]+=x;
            i+=i&-i;
        }
    }
};

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    string S;cin>>S;
    int N=si(S);
    
    vvll T(3);
    vl CN(3);
    
    auto ad=[&](){
        T[0].pb(mp(CN[0]-CN[1],CN[0]-CN[2]));
        T[1].pb(mp(CN[0]-CN[2],CN[0]-CN[1]));
        T[2].pb(mp(CN[1]-CN[2],CN[0]-CN[1]));
    };
    
    ad();
    
    for(int i=0;i<N;i++){
        if(S[i]=='I') CN[0]++;
        if(S[i]=='C') CN[1]++;
        if(S[i]=='P') CN[2]++;
        ad();
    }
    
    for(int i=0;i<3;i++) CN[i]=0;
    
    vector<BIT> BI(3);
    
    auto kasan=[&](mint x){
        {
            int s=lower_bound(all(T[0]),mp(CN[0]-CN[1],CN[0]-CN[2]))-T[0].begin();
            BI[0].add(s,x);
        }
        {
            int s=lower_bound(all(T[1]),mp(CN[0]-CN[2],CN[0]-CN[1]))-T[1].begin();
            BI[1].add(s,x);
        }
        {
            int s=lower_bound(all(T[2]),mp(CN[1]-CN[2],CN[0]-CN[1]))-T[2].begin();
            BI[2].add(s,x);
        }
    };
    
    auto sum=[&](){
        mint res=0;
        {
            int l=upper_bound(all(T[0]),mp(CN[0]-CN[1],CN[0]-CN[2]))-T[0].begin();
            int r=lower_bound(all(T[0]),mp(CN[0]-CN[1],(ll)INF))-T[0].begin();
            res+=BI[0].sum(l,r);
        }
        {
            int l=upper_bound(all(T[1]),mp(CN[0]-CN[2],CN[0]-CN[1]))-T[1].begin();
            int r=lower_bound(all(T[1]),mp(CN[0]-CN[2],(ll)INF))-T[1].begin();
            res+=BI[1].sum(l,r);
        }
        {
            int l=lower_bound(all(T[2]),mp(CN[1]-CN[2],(ll)-INF))-T[2].begin();
            int r=lower_bound(all(T[2]),mp(CN[1]-CN[2],CN[0]-CN[1]))-T[2].begin();
            res+=BI[2].sum(l,r);
        }
        return res;
    };
    
    
    for(int i=0;i<3;i++){
        mkunique(T[i]);
        BI[i].init(si(T[i]));
    }
    kasan(1);
    
    mint ans=-1;
    for(int i=0;i<N;i++){
        if(S[i]=='I') CN[0]++;
        if(S[i]=='C') CN[1]++;
        if(S[i]=='P') CN[2]++;
        mint x=sum();
        kasan(x);
        if(i==N-1) ans=x;
    }
    cout<<ans.val()<<endl;
}
accuracy: 1
time_ms: 830
memory_kb: 64892
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;

#define rep(i, s, t) for (ll i = (s); i < ll(t); i++)
#define all(x) x.begin(), x.end()

template <typename T> bool chmin(T &x, T y) {
    return x > y ? (x = y, true) : false;
}
template <typename T> bool chmax(T &x, T y) {
    return x < y ? (x = y, true) : false;
}

struct ___ {
    ___() {
        ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        cout << fixed << setprecision(15);
    }
} ___;

template <uint32_t mod> struct modint {
    using mm = modint;
    uint32_t x;
    modint() : x(0) {
    }
    modint(ll a = 0) : x((a % mod + mod) % mod) {
    }

    friend mm operator+(mm a, mm b) {
        a.x += b.x;
        if (a.x >= mod)
            a.x -= mod;
        return a;
    }

    friend mm operator-(mm a, mm b) {
        a.x -= b.x;
        if (a.x >= mod)
            a.x += mod;
        return a;
    }
    mm operator-() const {
        return mod - x;
    }
    friend mm operator*(mm a, mm b) {
        return (uint64_t)(a.x) * b.x;
    }
    friend mm &operator+=(mm &a, mm b) {
        return a = a + b;
    }
    friend mm &operator-=(mm &a, mm b) {
        return a = a - b;
    }
    friend mm &operator*=(mm &a, mm b) {
        return a = a * b;
    }

    friend istream &operator>>(istream &is, mm &a) {
        ll t;
        is >> t;
        a = mm(t);
        return is;
    }

    friend ostream &operator<<(ostream &os, mm a) {
        return os << a.x;
    }
};

const ll inf = INT_MAX / 4;
const ll min_pos = -inf;
const ll max_pos = inf;

template <class S, S (*op)(S, S), S (*e)(), class W> struct dynamic_segtree {
    dynamic_segtree() {
    }

  private:
    struct Node {
        W p;
        S x, prod;
        Node *l;
        Node *r;
        Node(W pos, S v) : p(pos), x(v), prod(v) {
            l = r = nullptr;
        }
    };
    using np = Node *;
    np root = nullptr;

    S val(np v) {
        return v != nullptr ? v->prod : e();
    }

    np apply(np v, W p, S &s, W L, W R) {
        if (!v) {
            v = new Node(p, s);
            return v;
        }
        if (v->p == p) {
            v->x = s;
            v->prod = op(val(v->l), op(v->x, val(v->r)));
            return v;
        }

        W M = (L + R) >> 1;
        if (p < M) {
            if (v->p < p)
                swap(p, v->p), swap(s, v->x);
            v->l = apply(v->l, p, s, L, M);
        } else {
            if (v->p > p)
                swap(p, v->p), swap(s, v->x);
            v->r = apply(v->r, p, s, M, R);
        }
        v->prod = op(val(v->l), op(v->x, val(v->r)));
        return v;
    }

    S query(np v, W l, W r, W L, W R) {
        if (r <= L || R <= l)
            return e();
        if (!v)
            return e();
        if (l <= L && R <= r)
            return v->prod;
        W M = (L + R) >> 1;
        S res = query(v->l, l, r, L, M);
        if (l <= v->p && v->p < r)
            res = op(res, v->x);
        return op(res, query(v->r, l, r, M, R));
    }

  public:
    void set(W pos, S s) {
        root = apply(root, pos, s, min_pos, max_pos);
    }
    S prod(W l, W r) {
        return query(root, l, r, min_pos, max_pos);
    }
    S get(W p) {
        return prod(p, p + 1);
    }
};

using mint = modint<998244353>;
mint op(mint l, mint r) {
    return l + r;
}
mint e() {
    return 0;
}
using segtree = dynamic_segtree<mint, op, e, ll>;

int main() {
    string str;
    cin >> str;
    ll n = ssize(str);
    vector<int> S(n);
    rep(i, 0, n) {
        if (str[i] == 'I')
            S[i] = 0;
        else if (str[i] == 'C')
            S[i] = 1;
        else
            S[i] = 2;
    }

    mint ans = 0;
    vector<ll> ofx(3, 0), ofy(3, 0);
    vector ss(3, map<ll, segtree>());

    auto all_shift = [&](ll t, ll dx, ll dy) {
        ofx[t] += dx;
        ofy[t] += dy;
    };
    auto add = [&](ll t, ll x, ll y, mint val) {
        mint from = ss[t][x - ofx[t]].get(y - ofy[t]);
        ss[t][x - ofx[t]].set(y - ofy[t], from + val);
    };

    auto prod = [&](ll t, ll x, ll sy, ll ty) {
        return ss[t][x - ofx[t]].prod(sy - ofy[t], ty - ofy[t]);
    };
    rep(t, 0, 3) {
        add(t, 0, 0, 1);
    }

    rep(i, 0, n) {
        mint val = 0;
        rep(t, 0, 3) {
            S[i] = (S[i] + 1) % 3;
            if (S[i] == 0) {
                all_shift(t, -1, 0);
            } else if (S[i] == 1) {
                all_shift(t, 1, -1);
            } else {
                all_shift(t, 0, 1);
            }

            val += prod(t, 0, 1, inf);
        }

        rep(t, 0, 3) {
            add(t, 0, 0, val);
        }
        if(i == n - 1) ans += val;
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 1750
memory_kb: 273916
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define all(v) (v).begin(),(v).end()
#define pb(a) push_back(a)
#define rep(i, n) for(int i=0;i<n;i++)
#define foa(e, v) for(auto&& e : v)
using ll = long long;
const ll MOD7 = 1000000007, MOD998 = 998244353, INF = (1LL << 60);
#define dout(a) cout<<fixed<<setprecision(10)<<a<<endl;

template<int MOD> struct Modint {
    long long val;
    constexpr Modint(long long v = 0) noexcept : val(v % MOD) { if (val < 0) val += MOD; }
    constexpr int mod() const { return MOD; }
    constexpr long long value() const { return val; }
    constexpr Modint operator - () const noexcept { return val ? MOD - val : 0; }
    constexpr Modint operator + (const Modint& r) const noexcept { return Modint(*this) += r; }
    constexpr Modint operator - (const Modint& r) const noexcept { return Modint(*this) -= r; }
    constexpr Modint operator * (const Modint& r) const noexcept { return Modint(*this) *= r; }
    constexpr Modint operator / (const Modint& r) const noexcept { return Modint(*this) /= r; }
    constexpr Modint& operator += (const Modint& r) noexcept {
        val += r.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }
    constexpr Modint& operator -= (const Modint& r) noexcept {
        val -= r.val;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr Modint& operator *= (const Modint& r) noexcept {
        val = val * r.val % MOD;
        return *this;
    }
    constexpr Modint& operator /= (const Modint& 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 Modint& r) const noexcept { return this->val == r.val; }
    constexpr bool operator != (const Modint& r) const noexcept { return this->val != r.val; }
    friend constexpr istream& operator >> (istream& is, Modint<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 Modint<MOD>& x) noexcept {
        return os << x.val;
    }
    constexpr Modint<MOD> pow(long long n) noexcept {
        if (n == 0) return 1;
        if (n < 0) return this->pow(-n).inv();
        Modint<MOD> ret = pow(n >> 1);
        ret *= ret;
        if (n & 1) ret *= *this;
        return ret;
    }
    constexpr Modint<MOD> inv() const noexcept {
        long long a = this->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 Modint<MOD>(u);
    }
};

const int MOD = MOD998;
using mint = Modint<MOD>;

template <class T> struct BIT {
    int n;
    vector<T> a;
    BIT(int m = 0) : n(m), a(m + 1, 0) {}
    void add(int x, T y) {
        x ++;
        while(x <= n) {
            a[x] += y;
            x += x & -x;
        }
    }
    T sum(int x) {
        T r = 0;
        while(x > 0) {
            r += a[x];
            x -= x & -x;
        }
        return r;
    }
    T sum(int x, int y) {
        return sum(y) - sum(x);
    }
};

const int base = 1 << 20;
vector<BIT<mint>> biti(base * 2), bitc(base * 2), bitp(base * 2);

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    string s; 
    cin >> s;
    
    vector<map<int, int>> mp(base * 2);
    vector<int> sz(base * 2, 0);
    {
        int c = 0, p = 0, i = 0;
        auto pro = [&]() -> void {
            mp[i - p + base][c - i] ++;
            mp[p - c + base][i - p] ++;
            mp[c - i + base][p - c] ++;
        };
        pro();
        foa(e, s) {
            if(e == 'I') i ++;
            else if(e == 'P') p ++;
            else c ++;
            pro();
        }
        rep(j, base * 2) {
            for(auto [x, y] : mp[j]) {
                mp[j][x] = sz[j] ++;
            }
        }
    }
    
    rep(i, base * 2) biti[i] = bitc[i] = bitp[i] = BIT<mint>(sz[i]);
    mint ans = 1;
    {
        int c = 0, p = 0, i = 0;
        auto add = [&]() -> void {
            biti[i - p + base].add(mp[i - p + base][c - i], ans);
            bitp[p - c + base].add(mp[p - c + base][i - p], ans);
            bitc[c - i + base].add(mp[c - i + base][p - c], ans);
        };
        add();
        auto sum = [&]() -> mint {
            mint r = 0;
            r += biti[i - p + base].sum(mp[i - p + base][c - i]);
            r += bitp[p - c + base].sum(mp[p - c + base][i - p]);
            r += bitc[c - i + base].sum(mp[c - i + base][p - c]);
            return r;
        };
        foa(e, s) {
            if(e == 'I') i ++;
            else if(e == 'P') p ++;
            else c ++;
            ans = sum();
            add();
        }
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 940
memory_kb: 683840
final_rank: 5

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#endif

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <queue>
using namespace std;
using ll = long long;
template<class A, class B> void chmax(A& a, const B& b){ if(a < b) a = b; }
template<class A, class B> void chmin(A& a, const B& b){ if(b < a) a = b; }
using PLL = pair<ll, ll>;
#define rep(i,n) for(ll i=0; i<ll(n); i++)

const int MOD = 998244353;
struct Modint {
    int x = 0;
    Modint& operator+=(const Modint& r){ x += r.x; if(x >= MOD){ x -= MOD; } return *this; }
    Modint& operator-=(const Modint& r){ if(x < r.x){ x += MOD; } x -= r.x; return *this; }
    Modint& operator*=(const Modint& r){ x = ll(x) * r.x % MOD; return *this; }
    Modint operator+(const Modint& r) const { auto v = *this; v += r; return v; }
    Modint operator-(const Modint& r) const { auto v = *this; v -= r; return v; }
    Modint operator*(const Modint& r) const { auto v = *this; v *= r; return v; }
};

struct FenwickTree {
    vector<Modint> A;
    FenwickTree(ll n = 0){
        A.assign(n+1, {0});
    }
    Modint sumh(ll r){
        Modint res = {0};
        while(r){
            res += A[r];
            r -= r & -r;
        }
        return res;
    }
    Modint sum(ll l, ll r){
        return sumh(r) - sumh(l);
    }
    void add(ll p, Modint x){
        p += 1;
        while(p < ll(A.size())){
            A[p] += x;
            p += p & -p;
        }
    }
};

pair<vector<ll>, vector<pair<ll,ll>>> desc(string A){
    ll N = A.size();
    vector<pair<ll,ll>> res(N+1);
    rep(i,N){
        auto [x,y] = res[i];
        if(A[i] == 'I'){
            y += 1;
        } else if(A[i] == 'P'){
            y -= 1; x -= 1;
        } else {
            x += 1;
        }
        res[i+1] = {x,y};
    }
    //for(auto [x,y] : res){ cout << "(" << x << "," << y << ")"; } cout << endl;
    ll min_x = 0;
    for(auto [x,y] : res) chmin(min_x , x);
    for(auto& [x,y] : res) x -= min_x;
    ll X = 0;
    for(auto [x,y] : res) chmax(X, x+1);
    vector<vector<ll>> buf(X);
    for(auto [x,y] : res) buf[x].push_back(y);
    for(auto& x : buf){
        sort(x.begin(), x.end());
        x.erase(unique(x.begin(),x.end()), x.end());
    }
    vector<ll> sz(X+1);
    rep(i,X) sz[i+1] = buf[i].size();
    rep(i,X) sz[i+1] += sz[i];
    for(auto& [x,y] : res){
        y = (lower_bound(buf[x].begin(), buf[x].end(), y) - buf[x].begin());
    }
    //for(auto [x,y] : res){ cout << "(" << x << "," << y << ")"; } cout << endl;
    return make_pair(move(sz), move(res));
}

void testcase(){
    string S; cin >> S;
    vector<vector<ll>> pos(3);
    vector<vector<pair<ll,ll>>> de(3);
    rep(t,3){
        //cout << "desc t = " << t << endl;
        auto [u,v] = desc(S);
        swap(pos[t], u);
        swap(de[t], v);
        for(char& c : S){
            if(c == 'I') c = 'P'; else if(c == 'P') c = 'C'; else c = 'I';
        }
    }
    //cout << "##" << endl;
    vector<FenwickTree> ds(3);
    rep(t,3) ds[t] = FenwickTree(pos[t].back() + 1);
    vector<Modint> dp(S.size()+1);
    dp[0].x = 1;
    rep(i,S.size()+1){
        if(i != 0){
            rep(t,3){
                auto [x,y] = de[t][i];
                dp[i] += ds[t].sum(pos[t][x], pos[t][x] + y);
            }
        }
        rep(t,3){
            auto [x,y] = de[t][i];
            ds[t].add(pos[t][x] + y, dp[i]);
        }
    }
    //for(auto a : dp) cout << a.x << " ";
    //cout << endl;
    cout << dp.back().x << "\n";
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    #ifdef NACHIA
    ll T; cin >> T; rep(t,T){
    #endif
    testcase();
    
    #ifdef NACHIA
    cout << "---------------------" << endl; }
    #endif
    return 0;
}
accuracy: 1
time_ms: 310
memory_kb: 122176
final_rank: 2

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#endif

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <queue>
using namespace std;
using ll = long long;
template<class A, class B> void chmax(A& a, const B& b){ if(a < b) a = b; }
template<class A, class B> void chmin(A& a, const B& b){ if(b < a) a = b; }
using PLL = pair<ll, ll>;
#define rep(i,n) for(ll i=0; i<ll(n); i++)

const int MOD = 998244353;
struct Modint {
    int x = 0;
    Modint& operator+=(const Modint& r){ x += r.x; if(x >= MOD){ x -= MOD; } return *this; }
    Modint& operator-=(const Modint& r){ if(x < r.x){ x += MOD; } x -= r.x; return *this; }
    Modint& operator*=(const Modint& r){ x = ll(x) * r.x % MOD; return *this; }
    Modint operator+(const Modint& r) const { auto v = *this; v += r; return v; }
    Modint operator-(const Modint& r) const { auto v = *this; v -= r; return v; }
    Modint operator*(const Modint& r) const { auto v = *this; v *= r; return v; }
};

struct FenwickTree {
    vector<Modint> A;
    FenwickTree(ll n = 0){
        A.assign(n+1, {0});
    }
    Modint sumh(ll r){
        Modint res = {0};
        while(r){
            res += A[r];
            r -= r & -r;
        }
        return res;
    }
    Modint sum(ll l, ll r){
        return sumh(r) - sumh(l);
    }
    void add(ll p, Modint x){
        p += 1;
        while(p < ll(A.size())){
            A[p] += x;
            p += p & -p;
        }
    }
};

pair<vector<ll>, vector<pair<ll,ll>>> desc(string A){
    ll N = A.size();
    vector<pair<ll,ll>> res(N+1);
    rep(i,N){
        auto [x,y] = res[i];
        if(A[i] == 'I'){
            y += 1;
        } else if(A[i] == 'P'){
            y -= 1; x -= 1;
        } else {
            x += 1;
        }
        res[i+1] = {x,y};
    }
    //for(auto [x,y] : res){ cout << "(" << x << "," << y << ")"; } cout << endl;
    ll min_x = 0;
    for(auto [x,y] : res) chmin(min_x , x);
    for(auto& [x,y] : res) x -= min_x;
    ll X = 0;
    for(auto [x,y] : res) chmax(X, x+1);
    vector<vector<ll>> buf(X);
    for(auto [x,y] : res) buf[x].push_back(y);
    for(auto& x : buf){
        sort(x.begin(), x.end());
        x.erase(unique(x.begin(),x.end()), x.end());
    }
    vector<ll> sz(X+1);
    rep(i,X) sz[i+1] = buf[i].size();
    rep(i,X) sz[i+1] += sz[i];
    for(auto& [x,y] : res){
        y = (lower_bound(buf[x].begin(), buf[x].end(), y) - buf[x].begin());
    }
    //for(auto [x,y] : res){ cout << "(" << x << "," << y << ")"; } cout << endl;
    return make_pair(move(sz), move(res));
}

void testcase(){
    string S; cin >> S;
    vector<vector<ll>> pos(3);
    vector<vector<pair<ll,ll>>> de(3);
    rep(t,3){
        //cout << "desc t = " << t << endl;
        auto [u,v] = desc(S);
        swap(pos[t], u);
        swap(de[t], v);
        for(char& c : S){
            if(c == 'I') c = 'P'; else if(c == 'P') c = 'C'; else c = 'I';
        }
    }
    //cout << "##" << endl;
    vector<FenwickTree> ds(3);
    rep(t,3) ds[t] = FenwickTree(pos[t].back() + 1);
    vector<Modint> dp(S.size()+1);
    dp[0].x = 1;
    rep(i,S.size()+1){
        if(i != 0){
            rep(t,3){
                auto [x,y] = de[t][i];
                dp[i] += ds[t].sum(pos[t][x], pos[t][x] + y);
            }
        }
        rep(t,3){
            auto [x,y] = de[t][i];
            ds[t].add(pos[t][x] + y, dp[i]);
        }
    }
    //for(auto a : dp) cout << a.x << " ";
    //cout << endl;
    cout << dp.back().x << "\n";
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    #ifdef NACHIA
    ll T; cin >> T; rep(t,T){
    #endif
    testcase();
    
    #ifdef NACHIA
    cout << "---------------------" << endl; }
    #endif
    return 0;
}
accuracy: 1
time_ms: 310
memory_kb: 122020
final_rank: 1

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

typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()

ll MOD = 998244353;

struct FT {
  map<ll, ll> raw;
  vll s;
  ll diff;
  FT() : s(2), diff(1) {}
  FT(ll n, ll diff) : s(n), diff(diff) {}
  void update(int pos, ll dif) {  // a[pos]+=dif
    raw[pos] += dif;
    raw[pos] %= MOD;
    bool isFirst=true;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      assert(isFirst);
      isFirst=false;
      resize();
    }
    pos += diff;
    for (; pos < sz(s); pos |= pos + 1) {
      s[pos] += dif;
      s[pos] %= MOD;
    }
  }
  ll query(int pos) {
    bool isFirst=true;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      assert(isFirst);
      resize();
    }
    pos += diff;
    ll res = 0;
    for (; pos > 0; pos &= pos - 1) {
      assert(pos<sz(s));
      res += s[pos - 1];
      res %= MOD;
    }
    return res;
  }
  void resize() {
    FT ft2(sz(s) * 3, diff + sz(s));
    for (auto& [key, val] : raw) {
      assert(0 <= key + ft2.diff && key + ft2.diff < sz(ft2.s));
      ft2.update(key, val);
    }
    s = ft2.s;
    diff = ft2.diff;
    // assert(raw == ft2.raw);
  }
};

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin.exceptions(cin.failbit);

  string S;
  cin >> S;
  int n = sz(S);

  ll ans = 0;
  vll dp(n + 1, 0);

  map<ll, FT> mpIC;  // mp[I-C][P-I]
  map<ll, FT> mpCP;  // mp[C-P][I-C]
  map<ll, FT> mpPI;  // mp[P-I][C-P]
  mpIC[0].update(0, 1);
  mpCP[0].update(0, 1);
  mpPI[0].update(0, 1);
  ll cntI = 0;
  ll cntC = 0;
  ll cntP = 0;
  rep(i, 0, n) {
    cntI += S[i] == 'I';
    cntC += S[i] == 'C';
    cntP += S[i] == 'P';
    dp[i + 1] += mpIC[cntI - cntC].query(cntP - cntI);
    dp[i+1]%=MOD;
    dp[i + 1] += mpCP[cntC - cntP].query(cntI - cntC);
    dp[i+1]%=MOD;
    dp[i + 1] += mpPI[cntP - cntI].query(cntC - cntP);
    dp[i+1]%=MOD;
    mpIC[cntI - cntC].update(cntP - cntI, dp[i + 1]);
    mpCP[cntC - cntP].update(cntI - cntC, dp[i + 1]);
    mpPI[cntP - cntI].update(cntC - cntP, dp[i + 1]);
  }

  cout << dp[n] << endl;
}
accuracy: 0.1
time_ms: 830
memory_kb: 219748
final_rank: 13

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

typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()

ll MOD = 998244353;

struct FT {
  map<ll, ll> raw;
  vll s;
  ll diff;
  FT() : s(16), diff(8) {}
  FT(ll n, ll diff) : s(n), diff(diff) {}
  void update(int pos, ll dif) {  // a[pos]+=dif
    raw[pos] += dif;
    raw[pos] %= MOD;
    bool isFirst=true;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      assert(isFirst);
      isFirst=false;
      resize();
    }
    pos += diff;
    for (; pos < sz(s); pos |= pos + 1) {
      s[pos] += dif;
      s[pos] %= MOD;
    }
  }
  ll query(int pos) {
    bool isFirst=true;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      assert(isFirst);
      resize();
    }
    pos += diff;
    ll res = 0;
    for (; pos > 0; pos &= pos - 1) {
      assert(pos<sz(s));
      res += s[pos - 1];
      res %= MOD;
    }
    return res;
  }
  void resize() {
    FT ft2(sz(s) * 3, diff + sz(s));
    for (auto& [key, val] : raw) {
      assert(0 <= key + ft2.diff && key + ft2.diff < sz(ft2.s));
      ft2.update(key, val);
    }
    s = ft2.s;
    diff = ft2.diff;
    // assert(raw == ft2.raw);
  }
};

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin.exceptions(cin.failbit);

  string S;
  cin >> S;
  int n = sz(S);

  ll ans = 0;
  vll dp(n + 1, 0);

  map<ll, FT> mpIC;  // mp[I-C][P-I]
  map<ll, FT> mpCP;  // mp[C-P][I-C]
  map<ll, FT> mpPI;  // mp[P-I][C-P]
  mpIC[0].update(0, 1);
  mpCP[0].update(0, 1);
  mpPI[0].update(0, 1);
  ll cntI = 0;
  ll cntC = 0;
  ll cntP = 0;
  rep(i, 0, n) {
    cntI += S[i] == 'I';
    cntC += S[i] == 'C';
    cntP += S[i] == 'P';
    dp[i + 1] += mpIC[cntI - cntC].query(cntP - cntI);
    dp[i+1]%=MOD;
    dp[i + 1] += mpCP[cntC - cntP].query(cntI - cntC);
    dp[i+1]%=MOD;
    dp[i + 1] += mpPI[cntP - cntI].query(cntC - cntP);
    dp[i+1]%=MOD;
    mpIC[cntI - cntC].update(cntP - cntI, dp[i + 1]);
    mpCP[cntC - cntP].update(cntI - cntC, dp[i + 1]);
    mpPI[cntP - cntI].update(cntC - cntP, dp[i + 1]);
  }

  cout << dp[n] << endl;
}
accuracy: 0.1
time_ms: 850
memory_kb: 247572
final_rank: 17

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

typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()

ll MOD = 998244353;

struct FT {
  map<ll, ll> raw;
  vll s;
  ll diff;
  FT() : s(16), diff(8) {}
  FT(ll n, ll diff) : s(n), diff(diff) {}
  void update(int pos, ll dif) {  // a[pos]+=dif
    raw[pos] += dif;
    raw[pos] %= MOD;
    bool isFirst=true;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      assert(isFirst);
      isFirst=false;
      resize();
    }
    pos += diff;
    for (; pos < sz(s); pos |= pos + 1) {
      s[pos] += dif;
      s[pos] %= MOD;
    }
  }
  ll query(int pos) {
    bool isFirst=true;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      assert(isFirst);
      resize();
    }
    pos += diff;
    ll res = 0;
    for (; pos > 0; pos &= pos - 1) {
      res += s[pos - 1];
      res %= MOD;
    }
    return res;
  }
  void resize() {
    FT ft2(sz(s) * 3, diff + sz(s));
    for (auto& [key, val] : raw) {
      assert(0 <= key + ft2.diff && key + ft2.diff < sz(ft2.s));
      ft2.update(key, val);
    }
    s = ft2.s;
    diff = ft2.diff;
    // assert(raw == ft2.raw);
  }
};

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin.exceptions(cin.failbit);

  string S;
  cin >> S;
  int n = sz(S);

  ll ans = 0;
  vll dp(n + 1, 0);

  map<ll, FT> mpIC;  // mp[I-C][P-I]
  map<ll, FT> mpCP;  // mp[C-P][I-C]
  map<ll, FT> mpPI;  // mp[P-I][C-P]
  mpIC[0].update(0, 1);
  mpCP[0].update(0, 1);
  mpPI[0].update(0, 1);
  ll cntI = 0;
  ll cntC = 0;
  ll cntP = 0;
  rep(i, 0, n) {
    cntI += S[i] == 'I';
    cntC += S[i] == 'C';
    cntP += S[i] == 'P';
    dp[i + 1] += mpIC[cntI - cntC].query(cntP - cntI);
    dp[i+1]%=MOD;
    dp[i + 1] += mpCP[cntC - cntP].query(cntI - cntC);
    dp[i+1]%=MOD;
    dp[i + 1] += mpPI[cntP - cntI].query(cntC - cntP);
    dp[i+1]%=MOD;
    mpIC[cntI - cntC].update(cntP - cntI, dp[i + 1]);
    mpCP[cntC - cntP].update(cntI - cntC, dp[i + 1]);
    mpPI[cntP - cntI].update(cntC - cntP, dp[i + 1]);
  }

  cout << dp[n] << endl;
}
accuracy: 0.1
time_ms: 850
memory_kb: 247568
final_rank: 16

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

typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()

ll MOD = 998244353;

struct FT {
  map<ll, ll> raw;
  vll s;
  ll diff;
  FT() : s(16), diff(8) {}
  FT(ll n, ll diff) : s(n), diff(diff) {}
  void update(int pos, ll dif) {  // a[pos]+=dif
    raw[pos] += dif;
    raw[pos] %= MOD;
    bool isFirst=true;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      assert(isFirst);
      isFirst=false;
      resize();
    }
    pos += diff;
    for (; pos < sz(s); pos |= pos + 1) {
      s[pos] += dif;
      s[pos] %= MOD;
    }
  }
  ll query(int pos) {
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      resize();
    }
    pos += diff;
    ll res = 0;
    for (; pos > 0; pos &= pos - 1) {
      res += s[pos - 1];
      res %= MOD;
    }
    return res;
  }
  void resize() {
    FT ft2(sz(s) * 3, diff + sz(s));
    for (auto& [key, val] : raw) {
      assert(0 <= key + ft2.diff && key + ft2.diff < sz(ft2.s));
      ft2.update(key, val);
    }
    s = ft2.s;
    diff = ft2.diff;
    // assert(raw == ft2.raw);
  }
};

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin.exceptions(cin.failbit);

  string S;
  cin >> S;
  int n = sz(S);

  ll ans = 0;
  vll dp(n + 1, 0);

  map<ll, FT> mpIC;  // mp[I-C][P-I]
  map<ll, FT> mpCP;  // mp[C-P][I-C]
  map<ll, FT> mpPI;  // mp[P-I][C-P]
  mpIC[0].update(0, 1);
  mpCP[0].update(0, 1);
  mpPI[0].update(0, 1);
  ll cntI = 0;
  ll cntC = 0;
  ll cntP = 0;
  rep(i, 0, n) {
    cntI += S[i] == 'I';
    cntC += S[i] == 'C';
    cntP += S[i] == 'P';
    dp[i + 1] += mpIC[cntI - cntC].query(cntP - cntI);
    dp[i+1]%=MOD;
    dp[i + 1] += mpCP[cntC - cntP].query(cntI - cntC);
    dp[i+1]%=MOD;
    dp[i + 1] += mpPI[cntP - cntI].query(cntC - cntP);
    dp[i+1]%=MOD;
    mpIC[cntI - cntC].update(cntP - cntI, dp[i + 1]);
    mpCP[cntC - cntP].update(cntI - cntC, dp[i + 1]);
    mpPI[cntP - cntI].update(cntC - cntP, dp[i + 1]);
  }

  cout << dp[n] << endl;
}
accuracy: 0.1
time_ms: 840
memory_kb: 247416
final_rank: 15

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

typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()

ll MOD = 998244353;

struct FT {
  map<ll, ll> raw;
  vll s;
  ll diff;
  FT() : s(16), diff(8) {}
  FT(ll n, ll diff) : s(n), diff(diff) {}
  void update(int pos, ll dif) {  // a[pos]+=dif
    raw[pos] += dif;
    raw[pos] %= MOD;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      resize();
    }
    pos += diff;
    for (; pos < sz(s); pos |= pos + 1) {
      s[pos] += dif;
      s[pos] %= MOD;
    }
  }
  ll query(int pos) {
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      resize();
    }
    pos += diff;
    ll res = 0;
    for (; pos > 0; pos &= pos - 1) {
      res += s[pos - 1];
      res %= MOD;
    }
    return res;
  }
  void resize() {
    FT ft2(sz(s) * 3, diff + sz(s));
    for (auto& [key, val] : raw) {
      assert(0 <= key + ft2.diff && key + ft2.diff < sz(ft2.s));
      ft2.update(key, val);
    }
    s = ft2.s;
    diff = ft2.diff;
    // assert(raw == ft2.raw);
  }
};

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin.exceptions(cin.failbit);

  string S;
  cin >> S;
  int n = sz(S);

  ll ans = 0;
  vll dp(n + 1, 0);

  map<ll, FT> mpIC;  // mp[I-C][P-I]
  map<ll, FT> mpCP;  // mp[C-P][I-C]
  map<ll, FT> mpPI;  // mp[P-I][C-P]
  mpIC[0].update(0, 1);
  mpCP[0].update(0, 1);
  mpPI[0].update(0, 1);
  ll cntI = 0;
  ll cntC = 0;
  ll cntP = 0;
  rep(i, 0, n) {
    cntI += S[i] == 'I';
    cntC += S[i] == 'C';
    cntP += S[i] == 'P';
    dp[i + 1] += mpIC[cntI - cntC].query(cntP - cntI);
    dp[i+1]%=MOD;
    dp[i + 1] += mpCP[cntC - cntP].query(cntI - cntC);
    dp[i+1]%=MOD;
    dp[i + 1] += mpPI[cntP - cntI].query(cntC - cntP);
    dp[i+1]%=MOD;
    mpIC[cntI - cntC].update(cntP - cntI, dp[i + 1]);
    mpCP[cntC - cntP].update(cntI - cntC, dp[i + 1]);
    mpPI[cntP - cntI].update(cntC - cntP, dp[i + 1]);
  }

  cout << dp[n] << endl;
}
accuracy: 0.1
time_ms: 860
memory_kb: 247412
final_rank: 18

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

typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()

ll MOD = 998244353;

struct FT {
  map<ll, ll> raw;
  vll s;
  ll diff;
  FT() : s(4), diff(2) {}
  FT(ll n, ll diff) : s(n), diff(diff) {}
  void update(int pos, ll dif) {  // a[pos]+=dif
    raw[pos] += dif;
    raw[pos] %= MOD;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      resize();
    }
    pos += diff;
    for (; pos < sz(s); pos |= pos + 1) {
      s[pos] += dif;
      s[pos] %= MOD;
    }
  }
  ll query(int pos) {
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      resize();
    }
    pos += diff;
    ll res = 0;
    for (; pos > 0; pos &= pos - 1) {
      res += s[pos - 1];
      res %= MOD;
    }
    return res;
  }
  void resize() {
    FT ft2(sz(s) * 3, diff + sz(s));
    for (auto& [key, val] : raw) {
      assert(0 <= key + ft2.diff && key + ft2.diff < sz(ft2.s));
      ft2.update(key, val);
    }
    s = ft2.s;
    diff = ft2.diff;
    // assert(raw == ft2.raw);
  }
};

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin.exceptions(cin.failbit);

  string S;
  cin >> S;
  int n = sz(S);

  ll ans = 0;
  vll dp(n + 1, 0);

  map<ll, FT> mpIC;  // mp[I-C][P-I]
  map<ll, FT> mpCP;  // mp[C-P][I-C]
  map<ll, FT> mpPI;  // mp[P-I][C-P]
  mpIC[0].update(0, 1);
  mpCP[0].update(0, 1);
  mpPI[0].update(0, 1);
  ll cntI = 0;
  ll cntC = 0;
  ll cntP = 0;
  rep(i, 0, n) {
    cntI += S[i] == 'I';
    cntC += S[i] == 'C';
    cntP += S[i] == 'P';
    dp[i + 1] += mpIC[cntI - cntC].query(cntP - cntI);
    dp[i+1]%=MOD;
    dp[i + 1] += mpCP[cntC - cntP].query(cntI - cntC);
    dp[i+1]%=MOD;
    dp[i + 1] += mpPI[cntP - cntI].query(cntC - cntP);
    dp[i+1]%=MOD;
    mpIC[cntI - cntC].update(cntP - cntI, dp[i + 1]);
    mpCP[cntC - cntP].update(cntI - cntC, dp[i + 1]);
    mpPI[cntP - cntI].update(cntC - cntP, dp[i + 1]);
  }

  cout << dp[n] << endl;
}
accuracy: 0.1
time_ms: 850
memory_kb: 238424
final_rank: 14

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

typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()

ll MOD = 998244353;

struct FT {
  map<ll, ll> raw;
  vll s;
  ll diff;
  FT() : s(4), diff(2) {}
  FT(ll n, ll diff) : s(n), diff(diff) {}
  void update(int pos, ll dif) {  // a[pos]+=dif
    raw[pos] += dif;
    raw[pos] %= MOD;
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      resize();
    }
    pos += diff;
    for (; pos < sz(s); pos |= pos + 1) {
      s[pos] += dif;
      s[pos] %= MOD;
    }
  }
  ll query(int pos) {
    while (pos + diff < 0 || pos + diff >= sz(s)) {
      resize();
    }
    pos += diff;
    ll res = 0;
    for (; pos > 0; pos &= pos - 1) {
      res += s[pos - 1];
      res %= MOD;
    }
    return res;
  }
  void resize() {
    FT ft2(sz(s) * 2, diff + sz(s) / 2);
    for (auto& [key, val] : raw) {
      // assert(0 <= key + ft2.diff && key + ft2.diff < sz(ft2.s));
      ft2.update(key, val);
    }
    s = ft2.s;
    diff = ft2.diff;
    // assert(raw == ft2.raw);
  }
};

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin.exceptions(cin.failbit);

  string S;
  cin >> S;
  int n = sz(S);

  ll ans = 0;
  vll dp(n + 1, 0);

  map<ll, FT> mpIC;  // mp[I-C][P-I]
  map<ll, FT> mpCP;  // mp[C-P][I-C]
  map<ll, FT> mpPI;  // mp[P-I][C-P]
  mpIC[0].update(0, 1);
  mpCP[0].update(0, 1);
  mpPI[0].update(0, 1);
  ll cntI = 0;
  ll cntC = 0;
  ll cntP = 0;
  rep(i, 0, n) {
    cntI += S[i] == 'I';
    cntC += S[i] == 'C';
    cntP += S[i] == 'P';
    dp[i + 1] += mpIC[cntI - cntC].query(cntP - cntI);
    dp[i+1]%=MOD;
    dp[i + 1] += mpCP[cntC - cntP].query(cntI - cntC);
    dp[i+1]%=MOD;
    dp[i + 1] += mpPI[cntP - cntI].query(cntC - cntP);
    dp[i+1]%=MOD;
    mpIC[cntI - cntC].update(cntP - cntI, dp[i + 1]);
    mpCP[cntC - cntP].update(cntI - cntC, dp[i + 1]);
    mpPI[cntP - cntI].update(cntC - cntP, dp[i + 1]);
  }

  cout << dp[n] << endl;
}
accuracy: 0.1
time_ms: 860
memory_kb: 196088
final_rank: 12

code_snippet: #include "bits/stdc++.h"

using namespace std;
using ll = long long;
constexpr ll mod = 998244353;

template <class T> struct fenwick_tree {
public:
	fenwick_tree() : _n(0) {}
	explicit fenwick_tree(int n) : _n(n), data(n) {}

	void add(int p, T x) {
		assert(0 <= p && p < _n);
		p++;
		while (p <= _n) {
			data[p - 1] += T(x);
			p += p & -p;
		}
	}

	T sum(int l, int r) {
		assert(0 <= l && l <= r && r <= _n);
		return sum(r) - sum(l);
	}

private:
	int _n;
	std::vector<T> data;

	T sum(int r) {
		T s = 0;
		while (r > 0) {
			s += data[r - 1];
			r -= r & -r;
		}
		return s % mod;
	}
};

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

	string s;
	cin >> s;

	vector<map<ll, map<ll, ll>>> icps(3);
	//0: ic //i-c, p-c, 座圧
	//1: ip //i-p, c-p, 座圧 
	//2: cp //c-p, i-p, 座圧

	for (auto&& x : icps) x[0][0] = 0;

	ll i = 0; ll c = 0; ll p = 0;
	for (int x = 0; x < s.size(); x++) {
		if (s[x] == 'I') i++;
		else if (s[x] == 'C') c++;
		else if (s[x] == 'P') p++;
		icps[0][i - c][p - c] = 0;
		icps[1][i - p][c - p] = 0;
		icps[2][c - p][i - p] = 0;
	}

	vector<map<ll, fenwick_tree<ll>>> fenwicks(3);
	for (int ix = 0; ix < 3; ++ix) {
		for (auto&& e1 : icps[ix]) {
			int i = 0;
			for (auto&& e2 : e1.second) e2.second = i++;
			fenwicks[ix][e1.first] = move(fenwick_tree<ll>(i));
		}
		fenwicks[ix][0].add(icps[ix][0][0], 1);
	}

	ll ans = 0;
	i = c = p = 0;
	for (int x = 0; x < s.size(); x++) {
		if (s[x] == 'I') i++;
		else if (s[x] == 'C') c++;
		else if (s[x] == 'P') p++;

		ll val = 0;
		val += fenwicks[0][i - c].sum(0, icps[0][i - c][p - c]);
		val += fenwicks[1][i - p].sum(0, icps[1][i - p][c - p]);
		val += fenwicks[2][c - p].sum(0, icps[2][c - p][i - p]);
		val %= mod;
		fenwicks[0][i - c].add(icps[0][i - c][p - c], val);
		fenwicks[1][i - p].add(icps[1][i - p][c - p], val);
		fenwicks[2][c - p].add(icps[2][c - p][i - p], val);
		ans = val;
	}
	cout << ans << endl;

	return 0;
}
accuracy: 1
time_ms: 3570
memory_kb: 605452
final_rank: 10

code_snippet: #include<bits/stdc++.h>
using namespace std;
template<class S,S(*op)(S,S),S(*e)()>
struct segtree{
  public:
    segtree():segtree(0){}
    segtree(int n):segtree(vector<S>(n,e())){}
    segtree(vector<S>v):_n((int)v.size()){
      log=ceil_pow2(_n);
      size=1<<log;
      d=vector<S>(2*size,e());
      for(int i=0;i<_n;++i)d[size+i]=v[i];
      for(int i=size-1;1<=i;--i){
        update(i);
      }
    }
    void set(int p,S x){
      p+=size;
      d[p]=x;
      for(int i=1;i<=log;++i)update(p>>i);
    }
    S get(int p){
      return d[p+size];
    }
    S prod(int l,int r){
      S sml=e(),smr=e();
      l+=size;
      r+=size;
      while(l<r){
        if(l&1)sml=op(sml,d[l++]);
        if(r&1)smr=op(d[--r],smr);
        l>>=1;
        r>>=1;
      }
      return op(sml,smr);
    }
  private:
    int _n,size,log;
    vector<S>d;
    void update(int k){
      d[k]=op(d[2*k],d[2*k+1]);
    }
    static int ceil_pow2(int n){
      int x=0;
      while((1U<<x)<(unsigned int)n)++x;
      return x;
    }
};
constexpr int mod=998244353;
int op(int a,int b){
  int sum=a+b;
  if(mod<=sum)sum-=mod;
  return sum;
}
int e(){
  return 0;
}
string s;
int n;
using ll=long long;
ll id(int x,int y){
  x+=(1<<20);
  y+=(1<<20);
  return(((ll)x)<<30)+y;
}
int main(){
  cin.tie(0)->sync_with_stdio(0);
  cin>>s;
  n=s.size();

  vector cum(n+1,vector<int>(3));
  vector<vector<pair<int,int>>>re(3);
  for(int i=0;i<n;++i){
    cum[i+1]=cum[i];
    for(int j=0;j<3;++j)if(s[i]=="CIP"[j])++cum[i+1][j];
  }
  for(int i=0;i<=n;++i)for(int j=0;j<3;++j){
    int key=cum[i][(j+1)%3]-cum[i][(j+2)%3];
    int r=cum[i][j]-cum[i][(j+1)%3];
    re[j].emplace_back(key,-1<<20);
    re[j].emplace_back(key,r);
  }
  vector<unordered_map<ll,int>>mp(3);
  for(int i=0;i<3;++i){
    sort(re[i].begin(),re[i].end());
    re[i].erase(unique(re[i].begin(),re[i].end()),re[i].end());
    for(int j=0;j<(int)re[i].size();++j){
      auto[x,y]=re[i][j];
      mp[i][id(x,y)]=j;
    }
  }
  vector<segtree<int,op,e>>seg(3);
  for(int i=0;i<3;++i){
    seg[i]=segtree<int,op,e>(re[i].size());
    seg[i].set(mp[i][id(0,0)],1);
  }
  int te=0;
  for(int i=1;i<=n;++i){
    te=0;
    for(int j=0;j<3;++j){
      int key=cum[i][(j+1)%3]-cum[i][(j+2)%3];
      int r=cum[i][j]-cum[i][(j+1)%3];
      te+=seg[j].prod(mp[j][id(key,-1<<20)],mp[j][id(key,r)]);
      if(mod<=te)te-=mod;
    }
    for(int j=0;j<3;++j){
      int key=cum[i][(j+1)%3]-cum[i][(j+2)%3];
      int r=cum[i][j]-cum[i][(j+1)%3];
      int val=seg[j].get(mp[j][id(key,r)]);
      val+=te;
      if(mod<=val)val-=mod;
      seg[j].set(mp[j][id(key,r)],val);
    }
  }
  cout<<te<<endl;
}
accuracy: 1
time_ms: 1650
memory_kb: 384928
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 998244353;
const int INF = 1001001001;
struct bit {
	int n;
	vector<ll> d;
	bit(int num) : n(num), d(num, 0) {}
	void resize(int num) {
		n = num;
		d.resize(num, 0);
	};
	void add(int p, int x) {
		p++;
		while (p <= n) {
			d[p - 1] += x;
			d[p - 1] % MOD;
			p += p & -p;
		}
		return;
	}
	ll sum(int l, int r) {
		return ((s(r) - s(l)) % MOD + MOD) % MOD;
	}
	ll s(int r) {
		ll res = 0;
		while (r > 0) {
			res += d[r - 1];
			res %= MOD;
			r -= r & -r;
		}
		return res;
	}
};
pair<int, int> conv(pair<int, int> p, int v) {
	if (v == 0) {
		return {p.first, p.second};
	} else if (v == 1) {
		return {p.second, p.first};
	} else {
		return {p.first - p.second, -p.first};
	}
}

// void show(pair<int, int> p) {
// 	cerr << p.first << " " << p.second << endl;
// }
// void show(vector<pair<int, int>> a) {
// 	for (auto p : a) show(p);
// }
// void show(vector<int> a) {
// 	for (auto p : a) cerr << p << " ";
// 	cerr << endl;
// }
// void show(vector<ll> a) {
// 	for (auto p : a) cerr << p << " ";
// 	cerr << endl;
// }
// void show(int x) {
// cerr << " :

int main() {
	string s;
	cin >> s;
	int n = s.size();
	vector<pair<int, int>> route;
	{
		pair<int, int> now = {0, 0};
		route.push_back(now);
		for (int i = 0; i < n; i++) {
			if (s[i] == 'I') {
				now.first++;
			} else if (s[i] == 'C') {
				now.first--;
				now.second--;
			} else {
				now.second++;
			}
			route.push_back(now);
		}
	}
	// show(route);
	vector<vector<pair<int, int>>> line(3);
	for (auto [x, y] : route) {
		for (int v = 0; v < 3; v++) {
			line[v].push_back(conv({x, y}, v));
		}
	}
	vector<int> minks(3, INF), maxks(3, -INF);
	for (int v = 0; v < 3; v++) {
		for (auto [k, i] : line[v]) {
			minks[v] = min(minks[v], k);
			maxks[v] = max(maxks[v], k);
		}
	}
	// show(minks);
	// show(maxks);
	vector<int> len(3);
	for (int v = 0; v < 3; v++) {
		len[v] = maxks[v] - minks[v] + 1;
	}
	// show(len);
	vector<vector<bit>> memo(3);
	vector<vector<vector<int>>> idxs(3);
	for (int v = 0; v < 3; v++) {
		memo[v].resize(len[v], bit(0));
		idxs[v].resize(len[v]);
		for (auto [k, i] : line[v]) {
			idxs[v][k - minks[v]].push_back(i);
		}
		for (int k = 0; k < len[v]; k++) {
			if (idxs[v][k].size() == 0) continue;
			sort(idxs[v][k].begin(), idxs[v][k].end());
			idxs[v][k].erase(unique(idxs[v][k].begin(), idxs[v][k].end()), idxs[v][k].end());
			// cerr << "#" << endl;
			// show(idxs[v][k]);
			// cerr << "#" << endl;
			memo[v][k].resize(idxs[v][k].size());
		}
	}

	auto add = [&](int v, int k, int i, ll val) {
		k -= minks[v];
		int convi = lower_bound(idxs[v][k].begin(), idxs[v][k].end(), i) - idxs[v][k].begin();
		// printf("  _ to %d\n", convi);
		memo[v][k].add(convi, val);
	};
	auto getsum = [&](int v, int k, int r) {
		k -= minks[v];
		int convr = lower_bound(idxs[v][k].begin(), idxs[v][k].end(), r) - idxs[v][k].begin();
		// printf("  _ tor %d\n", convr);
		return memo[v][k].sum(0, convr);
	};

	for (int v = 0; v < 3; v++) {
		auto [k, i] = conv({0, 0}, v);
		add(v, k, i, 1);
	}
	ll ans = 0;
	for (auto [x, y] : route) {
		// printf("(%d,%d)\n", x, y);
		ll tans = 0;
		for (int v = 0; v < 3; v++) {
			auto [k, i] = conv({x, y}, v);
			// printf("%d -> (%d,%d)\n", v, k, i);
			tans += getsum(v, k, i);
			tans %= MOD;
		}
		for (int v = 0; v < 3; v++) {
			auto [k, i] = conv({x, y}, v);
			add(v, k, i, tans);
		}
		// show(tans);
		ans = tans;
	}
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 286388
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 998244353;
const int INF = 1001001001;
struct bit {
	int n;
	vector<ll> d;
	bit(int num) : n(num), d(num, 0) {}
	void resize(int num) {
		n = num;
		d.resize(num, 0);
	};
	void add(int p, int x) {
		p++;
		while (p <= n) {
			d[p - 1] += x;
			d[p - 1] % MOD;
			p += p & -p;
		}
		return;
	}
	ll sum(int l, int r) {
		return ((s(r) - s(l)) % MOD + MOD) % MOD;
	}
	ll s(int r) {
		ll res = 0;
		while (r > 0) {
			res += d[r - 1];
			res %= MOD;
			r -= r & -r;
		}
		return res;
	}
};
pair<int, int> conv(pair<int, int> p, int v) {
	if (v == 0) {
		return {p.first, p.second};
	} else if (v == 1) {
		return {p.second, p.first};
	} else {
		return {p.first - p.second, -p.first};
	}
}

/*
// // void show(pair<int, int> p) {
cerr << p.first << " " << p.second << endl;
// }
// // void show(vector<pair<int, int>> a) {
// 	// for (auto p : a) show(p);
// }
// // void show(vector<int> a) {
for (auto p : a) cerr << p << " ";
cerr << endl;
// }
// // void show(vector<ll> a) {
for (auto p : a) cerr << p << " ";
cerr << endl;
// }
// // void show(int x) {
cerr << " :
*/

int main() {
	string s;
	cin >> s;
	int n = s.size();
	vector<pair<int, int>> route;
	{
		pair<int, int> now = {0, 0};
		route.push_back(now);
		for (int i = 0; i < n; i++) {
			if (s[i] == 'I') {
				now.first++;
			} else if (s[i] == 'C') {
				now.first--;
				now.second--;
			} else {
				now.second++;
			}
			route.push_back(now);
		}
	}
	// show(route);
	vector<vector<pair<int, int>>> line(3);
	for (auto [x, y] : route) {
		for (int v = 0; v < 3; v++) {
			line[v].push_back(conv({x, y}, v));
		}
	}
	vector<int> minks(3, INF), maxks(3, -INF);
	for (int v = 0; v < 3; v++) {
		for (auto [k, i] : line[v]) {
			minks[v] = min(minks[v], k);
			maxks[v] = max(maxks[v], k);
		}
	}
	// show(minks);
	// show(maxks);
	vector<int> len(3);
	for (int v = 0; v < 3; v++) {
		len[v] = maxks[v] - minks[v] + 1;
	}
	// show(len);
	vector<vector<bit>> memo(3);
	vector<vector<vector<int>>> idxs(3);
	for (int v = 0; v < 3; v++) {
		memo[v].resize(len[v], bit(0));
		idxs[v].resize(len[v]);
		for (auto [k, i] : line[v]) {
			idxs[v][k - minks[v]].push_back(i);
		}
		for (int k = 0; k < len[v]; k++) {
			if (idxs[v][k].size() == 0) continue;
			sort(idxs[v][k].begin(), idxs[v][k].end());
			idxs[v][k].erase(unique(idxs[v][k].begin(), idxs[v][k].end()), idxs[v][k].end());
			// cerr << "#" << endl;
			// show(idxs[v][k]);
			// cerr << "#" << endl;
			memo[v][k].resize(idxs[v][k].back() - idxs[v][k][0] + 1);
		}
	}

	auto add = [&](int v, int k, int i, ll val) {
		k -= minks[v];
		int convi = lower_bound(idxs[v][k].begin(), idxs[v][k].end(), i) - idxs[v][k].begin();
		// printf("  _ to %d\n", convi);
		memo[v][k].add(convi, val);
	};
	auto getsum = [&](int v, int k, int r) {
		k -= minks[v];
		int convr = lower_bound(idxs[v][k].begin(), idxs[v][k].end(), r) - idxs[v][k].begin();
		// printf("  _ tor %d\n", convr);
		return memo[v][k].sum(0, convr);
	};

	for (int v = 0; v < 3; v++) {
		auto [k, i] = conv({0, 0}, v);
		add(v, k, i, 1);
	}
	ll ans = 0;
	for (auto [x, y] : route) {
		// printf("(%d,%d)\n", x, y);
		ll tans = 0;
		for (int v = 0; v < 3; v++) {
			auto [k, i] = conv({x, y}, v);
			// printf("%d -> (%d,%d)\n", v, k, i);
			tans += getsum(v, k, i);
			tans %= MOD;
		}
		for (int v = 0; v < 3; v++) {
			auto [k, i] = conv({x, y}, v);
			add(v, k, i, tans);
		}
		// show(tans);
		ans = tans;
	}
	cout << ans << endl;
	return 0;
}
accuracy: 0.6
time_ms: 650
memory_kb: 1986096
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define vi vector<int>
#define vl vector<ll>
#define ov4(a, b, c, d, name, ...) name
#define rep3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep2(i, a, b) rep3(i, a, b, 1)
#define rep1(i, n) rep2(i, 0, n)
#define rep0(n) rep1(aaaaa, n)
#define rep(...) ov4(__VA_ARGS__, rep3, rep2, rep1, rep0) (__VA_ARGS__)
#define per(i, a, b) for(ll i = (a)-1; i >= (b); i--)
#define fore(e, v) for(auto&& e : v)
#define all(a) begin(a), end(a)
#define si(a) (int)(size(a))
#define lb(v, x) (lower_bound(all(v), x) - begin(v))
#define eb emplace_back

template<typename T, typename S> bool chmin(T& a, const S& b) {
    return a > b ? a = b, 1 : 0;
}

template<typename T, typename S> bool chmax(T& a, const S& b) {
    return a < b ? a = b, 1 : 0;
}

const int INF = 1e9 + 100;
const ll INFL = 3e18 + 100;


#define i128 __int128_t

struct _ {
    _() { cin.tie(0)->sync_with_stdio(0), cout.tie(0); }
} __;

constexpr int mod = 998244353;
struct mint {
    int x;
    mint(ll x_ = 0) : x(x_ % mod) {
        if (x < 0) x += mod;
    }
    mint operator-() {
        auto res = *this;
        res.x = (x ? mod - x : 0);
        return res;
    }
    mint& operator+=(mint r) {
        if((x += r.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(mint r) {
        if((x -= r.x) < 0) x += mod;
        return *this;
    }
    mint& operator*=(mint r) {
        x = 1LL * x * r.x % mod;
        return *this;
    }
    mint& operator/=(mint r) { return *this *= r.inv(); }
    friend mint operator+(mint a, mint b) { return a += b; }
    friend mint operator-(mint a, mint b) { return a -= b; }
    friend mint operator*(mint a, mint b) { return a *= b; }
    friend mint operator/(mint a, mint b) { return a /= b; }
    mint inv() const { return pow(mod - 2); }
    mint pow(ll b) const {
        mint a = *this, c = 1;
        while (b) {
            if (b & 1) c *= a;
            a *= a;
            b >>= 1;
        }
        return c;
    }
};
using vm = vector<mint>;

template<class S, S (*op)(S, S), S (*e)()> struct segtree {
    segtree(int n = 0) : segtree(vector<S>(n, e())) {}
    segtree(const vector<S>& v) : n(si(v)) {
        s = bit_ceil(unsigned(n));
        log = countr_zero(unsigned(s));
        d = vector<S>(2 * s, e());
        rep(i, n) d[s + i] = v[i];
        per(i, s, 1) update(i);
    }
    void set(int p, S x) {
        d[p += s] = x;
        rep(i, 1, log + 1) update(p >> i);
    }
    S prod(int l, int r) const {
        S sml = e(), smr = e();
        l += s, r += s;
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1, r >>= 1;
        }
        return op(sml, smr);
    }
    S all_prod() const { return d[1]; }
    template<typename F> int max_right(int l, F f) const {
        if (l == n) return n;
        l += s;
        S sm = e();
        do {
            while (~l & 1) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < s) {
                    l <<= 1;
                    if (f(op(sm, d[l]))) sm = op(sm, d[l++]);
                }
                return l - s;
            }
            sm = op(sm, d[l++]);
        } while ((l & -l) != l);
        return n;
    }
    template<typename F> int min_left(int r, F f) const {
        if (!r) return 0;
        r += s;
        S sm = e();
        do {
            r--;
            while(r > 1 and r & 1) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < s) {
                    r = (2 * r + 1);
                    if(f(op(d[r], sm))) sm = op(d[r--], sm);
                }
                return r + 1 - s;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

    private:
    int n, s, log;
    vector<S> d;
    void update(int k) { d[k] = op(d[k * 2], d[k * 2 + 1]); }
};

mint op(mint a, mint b) {return a + b;}
mint e() {return 0;}

ll N, B;
struct T{
    using vpl = vector<pair<ll, mint>>;
    using SEG = segtree<mint, op, e>;
    map<ll, vpl> naive_map;
    map<ll, SEG> seg_map;
    mint get(ll x, ll y) {
        // cerr << "get: " << x << " " << y << "\n";
        if (naive_map.count(x)) {
            if (naive_map[x].size() >= B) {
                SEG seg(2 * N + 1);
                for (auto &[_y, val] : naive_map[x]) {
                    seg.set(N + _y, seg.prod(N + _y, N + _y + 1) + val);
                }
                seg_map[x] = seg;
                naive_map.erase(x);
            } else {
                mint ret = 0;
                for (auto &[_y, val] : naive_map[x]) {
                    if (y < _y) ret += val;
                }
                return ret;
            }
        }
        if (seg_map.count(x)) {
            return seg_map[x].prod(N + y + 1, 2 * N + 1);
        }
        return 0;
    }
    void add(ll x, ll y, mint val) {
        // cerr << "add: " << x << " " << y << "\n";
        if (seg_map.count(x)) {
            mint tmp = seg_map[x].prod(N + y, N + y + 1);
            seg_map[x].set(N + y, tmp + val);
        } else {
            naive_map[x].emplace_back(y, val);
        }
    }
};

int main() {
    string S;
    cin >> S;
    N = si(S);
    B = 5 + 8 * sqrt(N);
    vm dp(N + 1, 0);
    dp[0] = 1;
    T IC, CP, PI;
    ll i_cnt = 0, c_cnt = 0, p_cnt = 0;
    rep(i, N) {
        IC.add(i_cnt - c_cnt, c_cnt - p_cnt, dp[i]);
        CP.add(c_cnt - p_cnt, p_cnt - i_cnt, dp[i]);
        PI.add(p_cnt - i_cnt, i_cnt - c_cnt, dp[i]);
        if (S[i] == 'I') i_cnt++;
        if (S[i] == 'C') c_cnt++;
        if (S[i] == 'P') p_cnt++;
        dp[i + 1] += IC.get(i_cnt - c_cnt, c_cnt - p_cnt);
        dp[i + 1] += CP.get(c_cnt - p_cnt, p_cnt - i_cnt);
        dp[i + 1] += PI.get(p_cnt - i_cnt, i_cnt - c_cnt);
    }
    // rep(i, N + 1) {
    //     cout << dp[i].x << " ";
    // }
    // cout << "\n";
    cout << dp[N].x << "\n";
}
accuracy: 1
time_ms: 2150
memory_kb: 243420
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define vi vector<int>
#define vl vector<ll>
#define ov4(a, b, c, d, name, ...) name
#define rep3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep2(i, a, b) rep3(i, a, b, 1)
#define rep1(i, n) rep2(i, 0, n)
#define rep0(n) rep1(aaaaa, n)
#define rep(...) ov4(__VA_ARGS__, rep3, rep2, rep1, rep0) (__VA_ARGS__)
#define per(i, a, b) for(ll i = (a)-1; i >= (b); i--)
#define fore(e, v) for(auto&& e : v)
#define all(a) begin(a), end(a)
#define si(a) (int)(size(a))
#define lb(v, x) (lower_bound(all(v), x) - begin(v))
#define eb emplace_back

template<typename T, typename S> bool chmin(T& a, const S& b) {
    return a > b ? a = b, 1 : 0;
}

template<typename T, typename S> bool chmax(T& a, const S& b) {
    return a < b ? a = b, 1 : 0;
}

const int INF = 1e9 + 100;
const ll INFL = 3e18 + 100;


#define i128 __int128_t

struct _ {
    _() { cin.tie(0)->sync_with_stdio(0), cout.tie(0); }
} __;

constexpr int mod = 998244353;
struct mint {
    int x;
    mint(ll x_ = 0) : x(x_ % mod) {
        if (x < 0) x += mod;
    }
    mint operator-() {
        auto res = *this;
        res.x = (x ? mod - x : 0);
        return res;
    }
    mint& operator+=(mint r) {
        if((x += r.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(mint r) {
        if((x -= r.x) < 0) x += mod;
        return *this;
    }
    mint& operator*=(mint r) {
        x = 1LL * x * r.x % mod;
        return *this;
    }
    mint& operator/=(mint r) { return *this *= r.inv(); }
    friend mint operator+(mint a, mint b) { return a += b; }
    friend mint operator-(mint a, mint b) { return a -= b; }
    friend mint operator*(mint a, mint b) { return a *= b; }
    friend mint operator/(mint a, mint b) { return a /= b; }
    mint inv() const { return pow(mod - 2); }
    mint pow(ll b) const {
        mint a = *this, c = 1;
        while (b) {
            if (b & 1) c *= a;
            a *= a;
            b >>= 1;
        }
        return c;
    }
};
using vm = vector<mint>;

template<class S, S (*op)(S, S), S (*e)()> struct segtree {
    segtree(int n = 0) : segtree(vector<S>(n, e())) {}
    segtree(const vector<S>& v) : n(si(v)) {
        s = bit_ceil(unsigned(n));
        log = countr_zero(unsigned(s));
        d = vector<S>(2 * s, e());
        rep(i, n) d[s + i] = v[i];
        per(i, s, 1) update(i);
    }
    void set(int p, S x) {
        d[p += s] = x;
        rep(i, 1, log + 1) update(p >> i);
    }
    S prod(int l, int r) const {
        S sml = e(), smr = e();
        l += s, r += s;
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1, r >>= 1;
        }
        return op(sml, smr);
    }
    S all_prod() const { return d[1]; }
    template<typename F> int max_right(int l, F f) const {
        if (l == n) return n;
        l += s;
        S sm = e();
        do {
            while (~l & 1) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < s) {
                    l <<= 1;
                    if (f(op(sm, d[l]))) sm = op(sm, d[l++]);
                }
                return l - s;
            }
            sm = op(sm, d[l++]);
        } while ((l & -l) != l);
        return n;
    }
    template<typename F> int min_left(int r, F f) const {
        if (!r) return 0;
        r += s;
        S sm = e();
        do {
            r--;
            while(r > 1 and r & 1) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < s) {
                    r = (2 * r + 1);
                    if(f(op(d[r], sm))) sm = op(d[r--], sm);
                }
                return r + 1 - s;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

    private:
    int n, s, log;
    vector<S> d;
    void update(int k) { d[k] = op(d[k * 2], d[k * 2 + 1]); }
};

mint op(mint a, mint b) {return a + b;}
mint e() {return 0;}

ll N, B;
struct T{
    using vpl = vector<pair<ll, mint>>;
    using SEG = segtree<mint, op, e>;
    map<ll, vpl> naive_map;
    map<ll, SEG> seg_map;
    mint get(ll x, ll y) {
        // cerr << "get: " << x << " " << y << "\n";
        if (naive_map.count(x)) {
            if (naive_map[x].size() >= B) {
                SEG seg(2 * N + 1);
                for (auto &[_y, val] : naive_map[x]) {
                    seg.set(N + _y, seg.prod(N + _y, N + _y + 1) + val);
                }
                seg_map[x] = seg;
                naive_map.erase(x);
            } else {
                mint ret = 0;
                for (auto &[_y, val] : naive_map[x]) {
                    if (y < _y) ret += val;
                }
                return ret;
            }
        }
        if (seg_map.count(x)) {
            return seg_map[x].prod(N + y + 1, 2 * N + 1);
        }
        return 0;
    }
    void add(ll x, ll y, mint val) {
        // cerr << "add: " << x << " " << y << "\n";
        if (seg_map.count(x)) {
            mint tmp = seg_map[x].prod(y, y + 1);
            seg_map[x].set(y, tmp + val);
        } else {
            naive_map[x].emplace_back(y, val);
        }
    }
};

int main() {
    string S;
    cin >> S;
    N = si(S);
    B = 5 + 8 * sqrt(N);
    vm dp(N + 1, 0);
    dp[0] = 1;
    T IC, CP, PI;
    ll i_cnt = 0, c_cnt = 0, p_cnt = 0;
    rep(i, N) {
        IC.add(i_cnt - c_cnt, c_cnt - p_cnt, dp[i]);
        CP.add(c_cnt - p_cnt, p_cnt - i_cnt, dp[i]);
        PI.add(p_cnt - i_cnt, i_cnt - c_cnt, dp[i]);
        if (S[i] == 'I') i_cnt++;
        if (S[i] == 'C') c_cnt++;
        if (S[i] == 'P') p_cnt++;
        dp[i + 1] += IC.get(i_cnt - c_cnt, c_cnt - p_cnt);
        dp[i + 1] += CP.get(c_cnt - p_cnt, p_cnt - i_cnt);
        dp[i + 1] += PI.get(p_cnt - i_cnt, i_cnt - c_cnt);
    }
    // rep(i, N + 1) {
    //     cout << dp[i].x << " ";
    // }
    // cout << "\n";
    cout << dp[N].x << "\n";
}
accuracy: 0.1
time_ms: 1440
memory_kb: 243416
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define vi vector<int>
#define vl vector<ll>
#define ov4(a, b, c, d, name, ...) name
#define rep3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep2(i, a, b) rep3(i, a, b, 1)
#define rep1(i, n) rep2(i, 0, n)
#define rep0(n) rep1(aaaaa, n)
#define rep(...) ov4(__VA_ARGS__, rep3, rep2, rep1, rep0) (__VA_ARGS__)
#define per(i, a, b) for(ll i = (a)-1; i >= (b); i--)
#define fore(e, v) for(auto&& e : v)
#define all(a) begin(a), end(a)
#define si(a) (int)(size(a))
#define lb(v, x) (lower_bound(all(v), x) - begin(v))
#define eb emplace_back

template<typename T, typename S> bool chmin(T& a, const S& b) {
    return a > b ? a = b, 1 : 0;
}

template<typename T, typename S> bool chmax(T& a, const S& b) {
    return a < b ? a = b, 1 : 0;
}

const int INF = 1e9 + 100;
const ll INFL = 3e18 + 100;


#define i128 __int128_t

struct _ {
    _() { cin.tie(0)->sync_with_stdio(0), cout.tie(0); }
} __;

constexpr int mod = 998244353;
struct mint {
    int x;
    mint(ll x_ = 0) : x(x_ % mod) {
        if (x < 0) x += mod;
    }
    mint operator-() {
        auto res = *this;
        res.x = (x ? mod - x : 0);
        return res;
    }
    mint& operator+=(mint r) {
        if((x += r.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(mint r) {
        if((x -= r.x) < 0) x += mod;
        return *this;
    }
    mint& operator*=(mint r) {
        x = 1LL * x * r.x % mod;
        return *this;
    }
    mint& operator/=(mint r) { return *this *= r.inv(); }
    friend mint operator+(mint a, mint b) { return a += b; }
    friend mint operator-(mint a, mint b) { return a -= b; }
    friend mint operator*(mint a, mint b) { return a *= b; }
    friend mint operator/(mint a, mint b) { return a /= b; }
    mint inv() const { return pow(mod - 2); }
    mint pow(ll b) const {
        mint a = *this, c = 1;
        while (b) {
            if (b & 1) c *= a;
            a *= a;
            b >>= 1;
        }
        return c;
    }
};
using vm = vector<mint>;

template<class S, S (*op)(S, S), S (*e)()> struct segtree {
    segtree(int n = 0) : segtree(vector<S>(n, e())) {}
    segtree(const vector<S>& v) : n(si(v)) {
        s = bit_ceil(unsigned(n));
        log = countr_zero(unsigned(s));
        d = vector<S>(2 * s, e());
        rep(i, n) d[s + i] = v[i];
        per(i, s, 1) update(i);
    }
    void set(int p, S x) {
        d[p += s] = x;
        rep(i, 1, log + 1) update(p >> i);
    }
    S prod(int l, int r) const {
        S sml = e(), smr = e();
        l += s, r += s;
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1, r >>= 1;
        }
        return op(sml, smr);
    }
    S all_prod() const { return d[1]; }
    template<typename F> int max_right(int l, F f) const {
        if (l == n) return n;
        l += s;
        S sm = e();
        do {
            while (~l & 1) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < s) {
                    l <<= 1;
                    if (f(op(sm, d[l]))) sm = op(sm, d[l++]);
                }
                return l - s;
            }
            sm = op(sm, d[l++]);
        } while ((l & -l) != l);
        return n;
    }
    template<typename F> int min_left(int r, F f) const {
        if (!r) return 0;
        r += s;
        S sm = e();
        do {
            r--;
            while(r > 1 and r & 1) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < s) {
                    r = (2 * r + 1);
                    if(f(op(d[r], sm))) sm = op(d[r--], sm);
                }
                return r + 1 - s;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

    private:
    int n, s, log;
    vector<S> d;
    void update(int k) { d[k] = op(d[k * 2], d[k * 2 + 1]); }
};

mint op(mint a, mint b) {return a + b;}
mint e() {return 0;}

ll N, B;
struct T{
    using vpl = vector<pair<ll, mint>>;
    using SEG = segtree<mint, op, e>;
    map<ll, vpl> naive_map;
    map<ll, SEG> seg_map;
    mint get(ll x, ll y) {
        // cerr << "get: " << x << " " << y << "\n";
        if (naive_map.count(x)) {
            if (naive_map[x].size() >= B) {
                SEG seg(2 * N + 1);
                for (auto &[_y, val] : naive_map[x]) {
                    seg.set(_y, seg.prod(_y, _y + 1) + val);
                }
                seg_map[x] = seg;
                naive_map.erase(x);
            } else {
                mint ret = 0;
                for (auto &[_y, val] : naive_map[x]) {
                    if (y < _y) ret += val;
                }
                return ret;
            }
        }
        if (seg_map.count(x)) {
            return seg_map[x].prod(N + y + 1, 2 * N + 1);
        }
        return 0;
    }
    void add(ll x, ll y, mint val) {
        // cerr << "add: " << x << " " << y << "\n";
        if (seg_map.count(x)) {
            mint tmp = seg_map[x].prod(y, y + 1);
            seg_map[x].set(y, tmp + val);
        } else {
            naive_map[x].emplace_back(y, val);
        }
    }
};

int main() {
    string S;
    cin >> S;
    N = si(S);
    B = 5 + 8 * sqrt(N);
    vm dp(N + 1);
    dp[0] = 1;
    T IC, CP, PI;
    IC.add(0, 0, 0);
    ll i_cnt = 0, c_cnt = 0, p_cnt = 0;
    rep(i, N) {
        IC.add(i_cnt - c_cnt, c_cnt - p_cnt, dp[i]);
        CP.add(c_cnt - p_cnt, p_cnt - i_cnt, dp[i]);
        PI.add(p_cnt - i_cnt, i_cnt - c_cnt, dp[i]);
        if (S[i] == 'I') i_cnt++;
        if (S[i] == 'C') c_cnt++;
        if (S[i] == 'P') p_cnt++;
        dp[i + 1] += IC.get(i_cnt - c_cnt, c_cnt - p_cnt);
        dp[i + 1] += CP.get(c_cnt - p_cnt, p_cnt - i_cnt);
        dp[i + 1] += PI.get(p_cnt - i_cnt, i_cnt - c_cnt);
    }
    // rep(i, N + 1) {
    //     cout << dp[i].x << " ";
    // }
    // cout << "\n";
    cout << dp[N].x << "\n";
}
accuracy: 0.1
time_ms: 1450
memory_kb: 243420
final_rank: 20