#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i,n) for(int i=0;i<n;++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 998244353;
#define MAX_N 200010

#define SUBMIT
//#define EXPERIMENT

string S;

set<string> all_pat;

// s[ind] と s[ind+1] を使われていない文字に変換
string GetNewStr(string s, int ind) {
    assert(s[ind] != s[ind+1]);
    if( (s[ind] == 'a' && s[ind+1] == 'b') || (s[ind] == 'b' && s[ind+1] == 'a') ) {
        s[ind] = s[ind+1] = 'c';
    }
    else if( (s[ind] == 'a' && s[ind+1] == 'c') || (s[ind] == 'c' && s[ind+1] == 'a') ) {
        s[ind] = s[ind+1] = 'b';
    }
    else {
        s[ind] = s[ind+1] = 'a';
    }
    return s;
}

// s から作成可能なすべての文字列を列挙
void MakeAllPat(string s) {
    if(all_pat.size() > 0) { return; }
    all_pat.insert(s);
    queue<string> que;
    que.push(s);
    while(!que.empty()) {
        string cur = que.front();
        que.pop();
        // 先頭から順に変換可能な場所を変換したパターンを作成
        for(int i = 0; i < cur.size()-1; ++i) {
            if(cur[i] != cur[i+1]) {
                string cand = GetNewStr(cur, i);
                if(all_pat.find(cand) == all_pat.end()) {
                    // 新しいパターンなら追加
                    all_pat.insert(cand);
                    que.push(cand);
                }
            }
        }
    }
}

// s を t にすることが可能なら true
bool IsChangeable(string s, string t) {
    MakeAllPat(s);
    return (all_pat.find(t) != all_pat.end());
}

// s を a= 0, b = 1, c = 2 としたときの総和 % 3 を返す
int ToNum(string s) {
    int ret = 0;
    REP(i, s.length()) {
        ret += s[i] - 'a';
        ret %= 3;
    }
    return ret;
}

void CheckDfs(vector<string>& all, string cur) {
    if(cur.length() == S.length()) {
        // 最終形のどこかは同じアルファベットが連続していなければならない
        bool isCont = false;
        REP(i, cur.length() - 1) {
            if(cur[i] == cur[i+1]) {
                isCont = true;
                break;
            }
        }
        if(isCont) { all.push_back(cur); }
        return;
    }
    CheckDfs(all, cur + 'a');
    CheckDfs(all, cur + 'b');
    CheckDfs(all, cur + 'c');
}

// S は、 a = 0, b = 1, c = 2 としたときの文字列の総和 % 3 が
// 一致するすべての文字列へ変換することが可能か確かめる
bool Check() {
    vector<string> all;
    CheckDfs(all, "");
    for(auto& all_s : all) {
        if((ToNum(S) == ToNum(all_s)) != IsChangeable(S, all_s)) {
            DBG("S: %s(%lld) all_s: %s(%lld) IsChangeable: %s \n",
                    S.c_str(), ToNum(S), all_s.c_str(), ToNum(all_s),
                    IsChangeable(S, all_s) ? "true" : "false");
            return false;
        }
    }
    return true;
}

// 全探索
ll Brute() {
    MakeAllPat(S);
    return all_pat.size();
}

// --------------------

ll mod_pat = 0;
ll dp[MAX_N][3][4][2];

// i 番目の文字を見ていて、現在の総和 % 3 が n 、一つ前の文字が prev、
// 今まで連続した領域が発生したことがあるかを flag (true => 連続領域あり)としたときの
// 文字列の総和 % 3 が mod_pat と一致する文字列パターンの数
ll Dfs(int i, int n, int prev, int flag) {
    if(i >= S.length()) {
        return ((n % 3) == mod_pat) ? flag : 0;
    }

    ll& ret = dp[i][n][prev][flag];
    if(~ret) { return ret; }
    ret = 0;

    // a を選択
    ret += Dfs(i+1, n, 0, (prev == 0) ? 1 : flag);
    ret %= MOD;
    // b を選択
    ret += Dfs(i+1, (n+1) % 3, 1, (prev == 1) ? 1 : flag);
    ret %= MOD;
    // c を選択
    ret += Dfs(i+1, (n+2) % 3, 2, (prev == 2) ? 1 : flag);
    ret %= MOD;

    return ret;
}

ll Solve() {
    // 実験の結果、S は、 a = 0, b = 1, c = 2 としたときの文字列の総和 % 3 が
    // 一致するすべての文字列へ変換することが可能で、それ以外へは変換不可能

    if(S.length() <= 3) { return Brute(); }

    // 遷移不可なら 1
    {
        bool isAllTheSame = true;
        REP(i, S.length() - 1) {
            if(S[i] != S[i+1]) {
                isAllTheSame = false;
                break;
            }
        }
        if(isAllTheSame) { return 1; }
    }

    mod_pat = ToNum(S);
    MINUS(dp);
    ll ret = Dfs(0, 0, 3, 0);
    // S そのものが連続して同じ文字がでないパターンだった場合、 -1 してしまうので
    // 調整
    int add = 1;
    REP(i, S.length() - 1) {
        if(S[i] == S[i+1]) {
            add = 0;
            break;
        }
    }
    ret = ret + add;
    ret %= MOD;
    return ret;
}

// --------------------

signed main()
{
#if defined(SUBMIT)
    cin >> S;
    //ll ans = Brute();
    ll ans = Solve();
    printf("%lld\n", ans);
#elif defined(EXPERIMENT)
    S = "abca";     // 0 + 1 + 2 + 0 = 3
    printf("%s\n", Check() ? "OK" : "NG");

    S = "aabb";      // 1 + 1 + 0 + 0 = 2
    all_pat.clear();
    printf("%s\n", Check() ? "OK" : "NG");

    S = "aabcb";      // 1 + 1 + 0 + 2 + 0 = 4
    all_pat.clear();
    printf("%s\n", Check() ? "OK" : "NG");
#else
    S = "bacabc"; // CheckDfs へ文字数を与えるため仮設定
    vector<string> all;
    CheckDfs(all, "");
    for(auto& all_s : all) {
        S = all_s;
        all_pat.clear();
        ll ans = Brute();
        ll cand = Solve();
        if(ans != cand) {
            DBG("ans: %lld cand: %lld S: %s\n", ans, cand, S.c_str());
            return 0;
        }
    }
    DBG("OK\n");
#endif
    return 0;
}


Measured memory_bytes: 53696