#include using namespace std; static const int CAP = 20; static const int INF = -1000000000; struct Key { int k,u,r,o; }; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); string S; if(!(cin >> S)) return 0; static int dp[21][21][21][21]; static int pp[21][21][21][21]; auto in_range = [&](int a,int b,int c,int d){ return (0<=a && a<=CAP && 0<=b && b<=CAP && 0<=c && c<=CAP && 0<=d && d<=CAP); }; // init for(int k=0;k<=CAP;k++) for(int u=0;u<=CAP;u++) for(int r=0;r<=CAP;r++) for(int o=0;o<=CAP;o++) dp[k][u][r][o] = INF; dp[0][0][0][0] = 0; vector cur; cur.reserve(10000); cur.push_back({0,0,0,0}); // used array reused each iteration static bool used[21][21][21][21]; for(char c : S){ // pp = dp (copy) memcpy(pp, dp, sizeof(dp)); // dp = pp (keep carry-over) memcpy(dp, pp, sizeof(dp)); // reset used and mark current cur as used (so we don't add duplicates) memset(used, 0, sizeof(used)); for(const auto &st : cur){ used[st.k][st.u][st.r][st.o] = true; } vector nxt; nxt.reserve(10000); auto push = [&](int a,int b,int c2,int d,int v){ if(!in_range(a,b,c2,d)) return; if(dp[a][b][c2][d] < v){ dp[a][b][c2][d] = v; } if(!used[a][b][c2][d]){ used[a][b][c2][d] = true; nxt.push_back({a,b,c2,d}); } }; // iterate only keys that were active in pp (represented by cur) for(const auto &st : cur){ int k = st.k, u = st.u, r = st.r, o = st.o; int val = pp[k][u][r][o]; if(val == INF) continue; // safety if(c == 'K'){ push(k+1, u, r, o, val); } else if(c == 'U'){ push(k-1, u+1, r, o, val); } else if(c == 'R'){ push(k, u-1, r+1, o, val); } else if(c == 'O'){ push(k, u, r-1, o+1, val); } else if(c == 'I'){ if(o > 0) push(k, u, r, o-1, val + 1); } if(c == '?'){ push(k+1, u, r, o, val); push(k-1, u+1, r, o, val); push(k, u-1, r+1, o, val); push(k, u, r-1, o+1, val); if(o > 0) push(k, u, r, o-1, val + 1); } } // **重要な修正**: cur を nxt で置換せず、cur に nxt を追加して「和集合」にする // こうすることで次の反復で pp.keys() に相当する dp 中の全キーを走査できます。 if(!nxt.empty()){ cur.insert(cur.end(), nxt.begin(), nxt.end()); // Optional: if cur grows too large, you can periodically compact it // by rebuilding cur from dp (scan dp for != INF). But typically not needed. } // note: we intentionally keep earlier cur entries (carry-over states), // because dp = pp preserved them and Python would iterate them next round as well. } int ans = 0; for(int k=0;k<=CAP;k++) for(int u=0;u<=CAP;u++) for(int r=0;r<=CAP;r++) for(int o=0;o<=CAP;o++) ans = max(ans, dp[k][u][r][o]); cout << ans << "\n"; return 0; }