Problem:
JOIOI の塔(Tower of JOIOI)
JOIOI の塔とは，1 人で遊ぶ円盤を使ったゲームである．
このゲームは，
J
，
O
，
I
のいずれかの文字が書かれたいくつかの円盤を用いて行う．円盤は直径が互いに異なり，ゲーム開始時にはこれらの円盤は直径の大きいものから順に下から上に向かって積まれている．あなたは，これらの円盤を用いて，出来るだけ多くのミニ JOIOI の塔を作りたい．ミニ JOIOI の塔とは 3 枚の円盤からなり，円盤の直径が小さいものから順に読んで
JOI
もしくは
IOI
と読めるものである．ただし，同じ円盤を2 度以上使うことはできない．
図:
JOIOII
からはミニ JOIOI の塔が 2 つ作れる
課題
用意された円盤に書かれた文字がそれぞれ円盤の直径が小さいものから順に長さ
N
の文字列
S
として与えられる．これらの円盤を使って作ることのできるミニ JOIOI の塔の個数の最大値を求めるプログラムを作成せよ．
制限
1 ≤
N
≤ 1 000 000      文字列
S
の長さ
入力
標準入力から以下のデータを読み込め．
1 行目には整数
N
が書かれている．
N
は文字列
S
の長さを表す．
2 行目には文字列
S
が書かれている．
出力
標準出力に，作ることのできるミニ JOIOI の塔の数の最大値を表す整数を 1 行で出力せよ．
入出力例
入力例 1
6
JOIIOI
出力例 1
2
JOIIOI
は
JOI
および
IOI
をそれぞれ 1 つずつ部分列として含んでおり，作ることのできるミニ JOIOI の塔は 2 つである．
入力例 2
5
JOIOI
出力例 2
1
部分列として
JOI
および
IOI
を含んでいるが，文字を 2 度以上使うことはできないため同時に取り出すことはできない．
入力例 3
6
JOIOII
出力例 3
2
この入出力例は問題文中の例に対応している．
入力例 4
15
JJOIIOOJOJIOIIO
出力例 4
4
問題文と自動審判に使われるデータは、
情報オリンピック日本委員会
が作成し公開している問題文と採点用テストデータです。

Submitted solutions:

code_snippet: #include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
bool used[1234567]; int n; string T;
int rec(string S, int R) {
	for (int i = 0; i < n; i++)used[i] = false;
	vector<pair<int, int>>vec; queue<int>Q; int cnt = 0;
	for (int i = S.size(); i >= 0; i--) {
		if (S[i] == 'I') { Q.push(i); }
		if (S[i] == 'O' && !Q.empty()) { int G = Q.front(); Q.pop(); vec.push_back(make_pair(i, G)); used[i] = true; used[G] = true; cnt++; }
		if (cnt == R)break;
	}
	sort(vec.begin(), vec.end()); int Y = 0;
	for (int i = 0; i < vec.size(); i++) {
		while (Y != n && (used[Y] == true || S[Y] == 'O')) { Y++; }
		if (Y >= vec[i].first)return i; used[Y] = true;
	}
	return cnt;
}
int main() {
	cin >> n >> T; int maxn = 0; int bef = -1;
	int L = 0, R = T.size(), M;
	while (true) {
		M = (L + R) / 2;
		int res1 = rec(T, M);
		int res2 = rec(T, M + 1);
		if (res1 == M && res2 < M + 1)break;
		if (res1 < M)R = M;
		if (res2 == M + 1)L = M;
	}
	cout << M << endl;
	return 0;
}
accuracy: 1
time_ms: 470
memory_kb: 14432
final_rank: 20

code_snippet: #include<iostream>
#include<algorithm>
using namespace std;
int n, JOI = 0, IOI = 0, OI = 0, I = 0, C = 0;
string k;
int main() {
	cin >> n >> k;
	for (int i = n - 1; i >= 0; i--) {
		if (k[i] == 'I') {
			if (OI) {
				IOI++;
				OI--;
			}
			else if (C) {
				IOI++;
				C--;
			}
			else I++;
		}
		if (k[i] == 'O') {
			if (I) {
				OI++;
				I--;
			}
			else if (IOI) {
				IOI--;
				C+=2;
			}
		}
		if (k[i] == 'J') {
			if (OI) {
				JOI++;
				OI--;
			}
			else if (C) {
				JOI++;
				C--;
			}
			else if (IOI) {
				I++;
				IOI--;
				JOI++;
			}
		}
	}
	cout << JOI + IOI + C / 2 << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 5152
final_rank: 2

code_snippet: #include <cstdio>
#include <algorithm>

#define rep(i, n) for(int i = 0; i < (n); ++i)

using namespace std;

int n;
char s[1000001];

// 関数judgeは、長さkの特定の部分列が存在するかどうかを判定します
bool judge(int k) {
    int a = 0, b = 0, c = 0;
    int p = k;
    // 文字列の後ろから前に向かって走査
    for(int i = n - 1; i >= 0; --i) {
        if(s[i] == 'J' && b > 0) {
            // 'J'が見つかり、'O'のペアが存在する場合
            --b;
            ++a;
        }
        if(s[i] == 'O' && c > 0) {
            // 'O'が見つかり、'I'のペアが存在する場合
            --c;
            ++b;
        }
        if(s[i] == 'I') {
            if(p > 0) {
                // 'I'が見つかり、'I'を処理する枠がある場合
                ++c;
                --p;
            }
            else if(b > 0) {
                // 'I'が見つかり、'O'のペアが存在する場合
                --b;
                ++a;
            }
        }
    }
    // 'J'のペアの数がkと等しいかを返す
    return a == k;
}

int main() {
    // 入力の読み込み
    scanf("%d%s", &n, s);
    int l = 0, r = n;
    // 二分探索で条件を満たす最大のkを探す
    while(r - l > 1) {
        int m = (l + r) / 2;
        if(judge(m)) {
            l = m;
        } else {
            r = m;
        }
    }
    // 結果の出力
    printf("%d\n", l);
    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 3952
final_rank: 3

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int N;
string S;
bool used[1000009];

bool check(int target) {
	for (int i = 0; i < N; i++) used[i] = false;
	int dep = 0, cnt = 0; vector<int> L1, L2;
	for (int i = N - 1; i >= 0; i--) {
		if (S[i] == 'I' && cnt < target) { dep += 1; cnt += 1; used[i] = true; }
		if (S[i] == 'O' && dep > 0) { dep -= 1; L1.push_back(i); used[i] = true; }
	}
	if (L1.size() < target) return false;
	reverse(L1.begin(), L1.end());
	for (int i = 0; i < N; i++) {
		if (used[i] == false && S[i] != 'O') L2.push_back(i);
	}
	if (L2.size() < target) return false;
	for (int i = 0; i < L1.size(); i++) {
		if (L1[i] < L2[i]) return false;
	}
	return true;
}

int main() {
	// Step 1. Input
	cin >> N >> S;

	// Step 2. Binary Search
	int cl = 0, cr = N, cm, maxn = 0;
	for (int i = 0; i < 30; i++) {
		cm = (cl + cr) / 2;
		bool ret = check(cm);
		if (ret == true) { cl = cm; maxn = max(maxn, cm); }
		else { cr = cm; }
	}
	
	// Step 3. Output
	cout << maxn << endl;
	return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 11228
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
int n,m,i,j,k,t,t1,u,v,a,b;
int ci,cj,cio,cjo,cioi,cjoi,cjoio,cioio;
char c;
int main() {
  cin>>n;
  for (i=0;i<n;i++) {
    cin>>c;
    if (c=='J') {
      cj++;
    }
    if (c=='O') {
      if (cj) {
        cj--;
        cjo++;
      }
      else if (ci) {
        ci--;
        cio++;
      }
      else if (cjoi) {
        cjoi--;
        cjoio++;
      }
      else if (cioi) {
        cioi--;
        cioio++;
      }
    }
    if (c=='I') {
      if (cjo) {
        cjo--;
        cjoi++;
      }
      else if (cio) {
        cio--;
        cioi++;
      }
      else if (cjoio) {
        cjoio--;
        cjo++;
        cioi++;
      }
      else if (cioio) {
      	cioio--;
        cioi++;
        cio++;
      }
      else ci++;
    }
    // cout<<ci<<' '<<cj<<' '<<cio<<' '<<cjo<<' '<<cioi<<' '<<cjoi<<' '<<cjoio<<endl;
  }
  cout<<cjoi+cioi+cjoio+cioio<<endl;
}
accuracy: 1
time_ms: 30
memory_kb: 3436
final_rank: 1

code_snippet: #include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
	cin.tie(0);
	ios_base::sync_with_stdio(false);
	int N; string S;
	cin >> N >> S;
	vector<int> I(N + 1), OI(N + 1), JOI(N + 1);
	for (int i = N - 1; i >= 0; --i) {
		if (S[i] == 'I') {
			I[i] = I[i + 1] + 1;
			OI[i] = OI[i + 1];
			JOI[i] = JOI[i + 1];
		}
		else if (S[i] == 'O') {
			I[i] = I[i + 1] - (I[i + 1] != 0 ? 1 : 0);
			OI[i] = OI[i + 1] + (I[i + 1] != 0 ? 1 : 0);
			JOI[i] = JOI[i + 1];
		}
		else {
			I[i] = I[i + 1];
			OI[i] = OI[i + 1] - (OI[i + 1] != 0 ? 1 : 0);
			JOI[i] = JOI[i + 1] + (OI[i + 1] != 0 ? 1 : 0);
		}
	}
	int J = 0, JO = 0, ans = 0;
	for (int i = 0; i < N; ++i) {
		int J_OI = min(J, OI[i]);
		int JO_I = min(JO, I[i]);
		int NJOI = J_OI + JO_I + JOI[i] + min(JO - JO_I, OI[i] - J_OI);
		ans = max(ans, NJOI);
		if (S[i] == 'J' || S[i] == 'I') {
			++J;
		}
		else if (J != 0) {
			--J; ++JO;
		}
	}
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 15844
final_rank: 15

code_snippet: #include <bits/stdc++.h>
#define err(args...) {}
#ifdef DEBUG
#include "_debug.cpp"
#endif
using namespace std;
using ll = long long;
using ld = long double;
template <typename T> using lim = numeric_limits<T>;
template <typename T> istream& operator>>(istream& is, vector<T>& a) { for(T& x : a) { is >> x; } return is; }
template <typename X, typename Y> istream& operator>>(istream& is, pair<X, Y>& p) { return is >> p.first >> p.second; }
template <typename Iter, typename T> int gt(Iter L, Iter R, T v) { return upper_bound(L, R, v) - L; }
template <typename Iter, typename T> int ge(Iter L, Iter R, T v) { return lower_bound(L, R, v) - L; }
template <typename Iter, typename T> int lt(Iter L, Iter R, T v) { return lower_bound(L, R, v) - L - 1; }
template <typename Iter, typename T> int le(Iter L, Iter R, T v) { return upper_bound(L, R, v) - L - 1; }
template <typename Bst, typename T> typename Bst::const_iterator gt(const Bst& bst, T v) { return bst.upper_bound(v); }
template <typename Bst, typename T> typename Bst::const_iterator ge(const Bst& bst, T v) { return bst.lower_bound(v); }
template <typename Bst, typename T> typename Bst::const_iterator lt(const Bst& bst, T v) { return bst.lower_bound(v) == bst.begin() ? bst.end() : --bst.lower_bound(v); }
template <typename Bst, typename T> typename Bst::const_iterator le(const Bst& bst, T v) { return bst.upper_bound(v) == bst.begin() ? bst.end() : --bst.upper_bound(v); }
template <typename T, typename Can> T bsearch(T L, T R, const Can& can, bool left_feasible = true) {
    static_assert(is_convertible<decltype(can), function<bool(T)>>::value, "can must be bool(T)");
    T& feasible = left_feasible ? L : R;
    T& infeasible = left_feasible ? R : L;
    while(R - L > 1) {
        T M = L + (R - L) / 2;
        (can(M) ? feasible : infeasible) = M;
    }
    return feasible;
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int n; string s;
    cin >> n >> s;
    cout << bsearch<int>(0, count(s.begin(), s.end(), 'I') + 1, [&](int k) {
        deque<int> J, Ihead, O, Itail;
        vector<int> head(n, -1), tail(n, -1);
        for(int i = n - 1; i >= 0; i--) {
            if(s[i] == 'J') {
                J.push_front(i);
            } else if(s[i] == 'O') {
                O.push_front(i);
            } else {
                (Itail.size() == k ? Ihead : Itail).push_front(i);
            }
        }
        for(auto o = O.rbegin(); o != O.rend(); o++) {
            if(not Itail.empty() and Itail.back() > *o) {
                tail[*o] = Itail.back();
                Itail.pop_back();
            }
        }
        for(int o : O) {
            if(tail[o] >= 0) {
                int i = Ihead.empty() ? n : Ihead.front(), j = J.empty() ? n : J.front();
                if(min(i, j) < o) {
                    head[o] = min(i, j);
                    (i < j ? Ihead : J).pop_front();
                }
            }
        }
        int cur = 0;
        for(int i = 0; i < n; i++) {
            cur += head[i] >= 0 and tail[i] >= 0;
        }
        return cur >= k;
    }) << endl;
    return 0;
}
accuracy: 1
time_ms: 280
memory_kb: 15888
final_rank: 19

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

int n;
string s;

// 右端からx個の'I'を終端と決め打ったときにx個構成できるか
bool f(int x){
    int icnt=0, ocnt=0, y=0, r=x;
    for(int i=n-1;i>=0;i--){
        if(s[i]=='J'){
            if(ocnt>0){
                y++;
                ocnt--;
            }
        }
        if(s[i]=='O'){
            if(icnt>0){
                ocnt++;
                icnt--;
            }
        }
        if(s[i]=='I'){
            if(r>0){
                icnt++;
                r--;
            }else if(ocnt>0){
                y++;
                ocnt--;
            }
        }
    }
    return y==x;
}

int solve(){
    cin >> n >> s;
    int ok = 0, ng = n/3+1;
    while(abs(ok-ng)>1){
        int mid = (ok+ng)/2;
        if(f(mid)){
            ok = mid;
        }else{
            ng = mid;
        }
    }
    cout << ok << endl;
    return 0;
}

int main(){
    solve();
    return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 3968
final_rank: 6

code_snippet: #include<algorithm>
#include<bitset>
#include<cassert>
#include<cfloat>
#include<climits>
#include<cmath>
#include<deque>
#include<functional>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<string>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<vector>

using namespace std;

using lint = long long;
using P = pair<int, int>;
using LLP = pair<long long, long long>;

#define REP(i, x, n) for(int i = (x), i##_len = (int)(n) ; i < i##_len ; ++i)
#define rep(i, n) for(int i = 0, i##_len = (int)(n) ; i < i##_len ; ++i)
#define reps(i, n) for(int i = 1, i##_len = (int)(n) ; i <= i##_len ; ++i)
#define rrep(i, n) for(int i = (int)(n) - 1 ; i >= 0 ; --i)
#define rreps(i, n) for(int i = (int)(n) ; i > 0 ; --i)
#define SORT(x) sort((x).begin(), (x).end())
#define SORT_INV(x) sort((x).rbegin(), (x).rend())
#define REVERSE(x) reverse((x).begin(), (x).end())
#define TWINS(x) cout << ((x) ? "Yay!" : ":(") << '\n'

constexpr int IINF = (1 << 30) - 1;
constexpr long long LLINF = 1LL << 61;
constexpr double EPS = 1e-10;

constexpr int dx4[] = {1, 0, -1, 0}, dy4[] = {0, 1, 0, -1};
constexpr int dx8[] = {1, 1, 0, -1, -1, -1, 0, 1}, dy8[] = {0, -1, -1, -1, 0, 1, 1, 1};

template<typename T>
T meguru_search(T ok, T ng, function<bool(T)> check){
    while(max(ok, ng) - min(ok, ng) > T(1)){
        T mid = (ok + ng) / T(2);
        if(check(mid)){
            ok = mid;
        }else{
            ng = mid;
        }
    }
    return ok;
}

template<typename T>
bool chmax(T& a, T b){
    if(a < b){
        a = b;
        return true;
    }
    return false;
}

template<typename T>
bool chmin(T& a, T b){
    if(b < a){
        a = b;
        return true;
    }
    return false;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);

    int n;
    cin >> n;

    string s;
    cin >> s;

    auto check = [&](int mid){
        vector<int> ipos;
        vector<bool> used(n, false);
        rrep(i, n){
            if((int)ipos.size() >= mid){
                break;
            }
            if(s[i] == 'I'){
                ipos.emplace_back(i);
                used[i] = true;
            }
        }

        if((int)ipos.size() < mid){
            return false;
        }

        vector<int> opos;
        rrep(i, n){
            if((int)opos.size() >= mid){
                break;
            }
            if(s[i] == 'O' && i < ipos[opos.size()]){
                opos.emplace_back(i);
            }
        }

        if((int)opos.size() < mid){
            return false;
        }

        int cnt = 0;
        rrep(i, n){
            if(cnt >= mid){
                return true;
            }
            if(used[i] || s[i] == 'O'){
                continue;
            }
            if(i < opos[cnt]){
                ++cnt;
            }
        }

        return cnt >= mid;
    };

    int ans = meguru_search<int>(0, n, check);
    cout << ans << endl;

    cout << flush;

    return 0;
}
accuracy: 1
time_ms: 270
memory_kb: 9016
final_rank: 16

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int,int> P;

int N;
string S;
bool used[1000005];

bool check(int x){
    memset(used,0,N);
    int idx = N-1;
    vector<int> lis;
    for (int i = 0;i < x;i++){
        while(S[idx] != 'I'){
            //cout << S[idx] << endl;
            idx--;
            if(idx < 0) return false;
        }
        used[idx] = true;
        lis.push_back(idx);
        idx--;
    }
    vector<int> lis2;
    idx = N-1;
    for (int i = 0;i < x;i++){
        while(!(idx < lis[i] && S[idx] == 'O') ){
            idx--;
            if(idx < 0) return false;
        }
        used[idx] = true;
        lis2.push_back(idx);
        idx--;
    }
    idx = N-1;
    for (int i = 0;i < x;i++){
        while(!(idx < lis2[i] && (S[idx] == 'I' || S[idx] == 'J') && used[idx] == false) ){
            idx--;
            if(idx < 0) return false;
        }
        used[idx] = true;
        idx--;
    }
    return true;
}

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

    cin >> N >> S;

    int high = N, low = 0;
    while(high-low != 1){
        int mid = (high+low)/2;
        if(check(mid)) low = mid;
        else high = mid;
    }

    cout << low << endl;

    return 0;

}
accuracy: 1
time_ms: 220
memory_kb: 10016
final_rank: 14

code_snippet: #include<iostream>
#include<cstdio>
using namespace std;

int main()
{
   int n;
   char s[1000010];
   
   cin >> n;
   scanf("%s",s);
   
   int l,r,mid,jj,oo,ii,isum;
   l = 0;
   r = n-1;
  while(l < r){
       jj = 0;
       oo = 0;
       ii = 0;
       isum = 0;
       mid = (l+r+1)/2;
       for(int i=n-1;i>=0;i--){
           if(s[i] == 'I' && isum < mid){
               ii++;
               isum++;
           }
           else if(ii > 0 && s[i] == 'O'){
               oo++;
               ii--;
           }
           else if(oo > 0 && s[i] != 'O'){
               jj++;
               oo--;
           }
       }
       
       if(jj >= mid) l = mid;
       else r = mid-1;
       
   }
    
    cout << l << endl;
    
    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 4200
final_rank: 5

code_snippet: #include<iostream>
#include<vector>
#include<string>
using namespace std;

bool C(int N, string S, int k){
	int cnt = 0, cnt2 = 0, cnt3 = 0;
	for(int i = N - 1; i >= 0; i--){
		if(S[i] == 'I' && cnt < k) cnt++;
		else if(S[i] == 'O' && cnt2 < cnt) cnt2++;
		else if((S[i] == 'J' || S[i] == 'I') && cnt3 < cnt2) cnt3++;
	}
	if(cnt3 == k) return true;
	return false;
}

int main(){
	int N;
	cin >> N;
	string S;
	cin >> S;
	int lb = 0, ub = N / 3 + 1;
	while(ub - lb > 1){
		int mid = lb + (ub - lb) / 2;
		if(C(N, S, mid)) lb = mid;
		else ub = mid;
	}
	cout << lb << endl;
	return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 4988
final_rank: 11

code_snippet: #include <bits/stdc++.h>

#define FOR(i,a,b) for(int i= (a); i<((int)b); ++i)
#define RFOR(i,a) for(int i=(a); i >= 0; --i)
#define FOE(i,a) for(auto i : a)
#define ALL(c) (c).begin(), (c).end()
#define RALL(c) (c).rbegin(), (c).rend()
#define SUM(x) std::accumulate(ALL(x), 0LL)
#define MIN(v) *std::min_element(v.begin(), v.end())
#define MAX(v) *std::max_element(v.begin(), v.end())
#define EXIST(v,x) (std::find(v.begin(), v.end(), x) != v.end())
#define BIT_ON(bit, i) (((bit >> i) & 1) > 0)
#define BIT_COUNT(bit) (__builtin_popcount(bit))

typedef long long LL;
template<typename T> std::vector<T> make_v(size_t a){return std::vector<T>(a);}
template<typename T,typename... Ts> auto make_v(size_t a, Ts... ts){ return std::vector<decltype(make_v<T>(ts...))>(a,make_v<T>(ts...));}    // C++14
template<typename T,typename V> typename std::enable_if<std::is_class<T>::value==0>::type fill_v(T &t,const V &v){t=v;}
template<typename T,typename V> typename std::enable_if<std::is_class<T>::value!=0>::type fill_v(T &t,const V &v){for(auto &e:t) fill_v(e,v);}
template<class T> inline T ceil(T a, T b) { return (a + b - 1) / b; }
template<class T> inline void print(T x) { std::cout << x << std::endl; }
template<class T> inline void print_vec(const std::vector<T> &v) { for (int i = 0; i < v.size(); ++i) {  if (i != 0) {std::cout << " ";} std::cout << v[i];} std::cout << "\n"; }
inline bool inside(long long y, long long x, long long H, long long W) {return 0 <= y and y < H and 0 <= x and x < W; }
template<class T> inline double euclidean_distance(T y1, T x1, T y2, T x2) { return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); }
template<class T> inline double manhattan_distance(T y1, T x1, T y2, T x2) { return abs(x1 - x2) + abs(y1 - y2); }
template<typename T> T &chmin(T &a, const T &b) { return a = std::min(a, b); }
template<typename T> T &chmax(T &a, const T &b) { return a = std::max(a, b); }

template<class T> inline std::vector<T> unique(std::vector<T> v) {
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    return v;
}
// 初項s, 交差dのn個の数列の和
long long sum_of_arithmetic_progression(long long s, long long d, long long n) {
    return n * (2 * s + (n - 1) * d) / 2;
}

// 2のべき乗数かどうか
bool is_power_of_two(long long x) {
    return !(x & (x - 1));
}

// aとbの最大公約数 O(log min(a, b))
long long gcd(long long a, long long b) {
    if (b == 0) { return a; }
    return gcd(b, a % b);
}

// 数列vの最大公約数 O(N log d)
long long gcd(std::vector<long long> &v) {
    long long ans = v[0];
    for (int i = 1; i < (int)v.size(); ++i) {
        ans = gcd(ans, v[i]);
    }
    return ans;
}

// aとbの最小公倍数 O(log min(a, b))
long long lcm(long long a, long long b) {
    long long g = gcd(a, b);
    return a / g * b;
}

const int INF = 1u << 30u;
const long long LINF = 1ull << 60u;
const double EPS = 1e-9;
const long double PI = acos(-1.0);
const std::vector<int> dy2 = {0, 1}, dx2 = {1, 0};  // 右，下
const std::vector<int> dy4 = {0, 1, 0, -1}, dx4 = {1, 0, -1, 0};    // 右，下，左，上
const std::vector<int> dy8 = { 0, -1, 0, 1, 1, -1, -1, 1 }, dx8 = { 1, 0, -1, 0, 1, 1, -1, -1 };

using namespace std;

// x個つくれる
bool ok(const long long x, string &s) {
    int num = x;

    int ans = 0;
    int num_i = 0, num_oi = 0;
    for (int i = s.size() - 1; i >= 0; --i) {
        if (s[i] == 'J') {
            if (num_oi > 0) {
                num_oi--;
                ans++;
            }
        }
        else if (s[i] == 'O') {
            if (num_i > 0) {
                num_i--;
                num_oi++;
            }
        }
        else if (s[i] == 'I') {
            num_i++;
            num--;
            if (num < 0 and num_oi > 0) {
                num_i--;
                num_oi--;
                ans++;
            }
        }
    }

    return ans >= x;
}

// 開区間(low, high)で条件を満たす一番右
// なければlowを返す
int binary_search_right(long long low, long long high, string &s) {
    // (low, high)
    while (high - low > 1) {
        long long middle = (low + high) / 2;
        if (ok(middle, s)) {
            low = middle;
        }
        else {
            high = middle;
        }
    }

    return low;
}


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

    LL N;
    cin >> N;
    string S;
    cin >> S;

    print(binary_search_right(-1, S.size(), S));

    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 4644
final_rank: 8

code_snippet: #include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define lol(i,n) for(int i=0;i<n;i++)
#define mod 1000000007
typedef long long ll;

using namespace std;
string s;int n;
bool F(int x){
    int a=0,b=0;
    lol(i,n){
	if(s[i]=='I'&&x)x--,a++;
	else if(s[i]=='O'&&a)a--,b++;
	else if(s[i]!='O')b=max(0,b-1);
    }
    return (x+a+b==0);
}
int main(){
    cin>>n>>s;
    reverse(s.begin(),s.end());
    int l=0,r=n,m;
    while(l<r-1){
	m=(l+r)/2;
	if(F(m))l=m;
	else r=m;
    }
    cout<<l<<endl;
    return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 3996
final_rank: 7

code_snippet: #include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


int N,length;
char buf[1000001];
bool used[1000001];


bool can_make(int tower_num){

	int tail_I_num = 0,mid_O_num = 0;
	for(int i = 0; i < length; i++)used[i] = false;

	for(int i = length-1; (i >= 0) && (tail_I_num < tower_num || mid_O_num < tower_num); i--){
		if(buf[i] == 'I'){
			if(tail_I_num < tower_num){
				tail_I_num++;
				used[i] = true;
			}
		}else if(buf[i] == 'O'){
			if(mid_O_num < tower_num && mid_O_num < tail_I_num){
				mid_O_num++;
				used[i] = true;
			}
		}
	}

	if(tail_I_num < tower_num || mid_O_num < tower_num)return false;

	int count = 0;
	mid_O_num = 0;

	for(int i = length-1; i >= 0 && count < tower_num; i--){
		if(buf[i] == 'I' || buf[i] == 'J'){
			if(used[i] == false && mid_O_num > 0){
				count++;
				mid_O_num--;
			}
		}else{ //buf[i] == 'O'
			if(used[i]){
				mid_O_num++;
			}
		}
	}

	return count == tower_num;
}


int main(){

	scanf("%d",&N);
	scanf("%s",buf);

	for(length = 0; buf[length] != '\0'; length++);

	int ans = 0;
	int left = 0, right = N,m = (left+right)/2;

	while(left <= right){

		if(can_make(m)){
			ans = m;
			left = m+1;
		}else{
			right = m-1;
		}
		m = (left+right)/2;
	}

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

	return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 5160
final_rank: 12

code_snippet: #include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cmath>
#include <iomanip>
#include <cassert>
#include <bitset>
using namespace std;

typedef pair<int, int> P;
#define rep(i, n) for (int i=0; i<(n); i++)
#define all(c) (c).begin(), (c).end()
#define uniq(c) c.erase(unique(all(c)), (c).end())
#define _1 first
#define _2 second
#define pb push_back
#define INF 1145141919
#define MOD 1000000007

int N;
char S[1000001];

bool f(int X) {
  int rem = X;
  int s_i = 0, s_io = 0, s_ioi = 0;
  rep(i, N) {
    if (S[i] == 'I') {
      if (rem > 0) {
        rem--;
        s_i++;
      }
      else {
        if (s_io > 0) s_ioi++, s_io--;
      }
    }
    else if (S[i] == 'O') {
      if (s_i > 0) s_io++, s_i--;
    }
    else {
      // J
      if (s_io > 0) s_ioi++, s_io--;
    }
  }
  return s_ioi >= X;
}

signed main() {
  ios::sync_with_stdio(false); cin.tie(0);
  cin >> N;
  cin >> S;
  reverse(S, S+N);
  int lo = 0, hi = N;
  while (hi - lo > 1) {
    int mid = (lo + hi) / 2;
    if (f(mid)) lo = mid;
    else hi = mid;
  }
  cout << lo << "\n";
  return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 4108
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pb push_back
#define x first
#define y second
#define pii pair<int, int>
#define p3i pair<pii, int>
#define pll pair<ll, ll>
#define p3l pair<pll, ll>
#define lseg L, (L+R)/2, N*2+1
#define rseg (L+R)/2+1, R, N*2+2
#define ub upper_bound
#define lb lower_bound
#define pq priority_queue
#define MN 1000000007
#define fox(k, x) for (int k=0; k<x; ++k)
#define fox1(k, x) for (int k=1; k<=x; ++k)
#define foxr(k, x) for (int k=x-1; k>=0; --k)
#define fox1r(k, x) for (int k=x; k>0; --k)
#define ms multiset
#define flood(x) memset(x, 0x3f3f3f3f, sizeof x)
#define drain(x) memset(x, 0, sizeof x)

int lo, mid, hi, n, cnt[3];
string s;
bool check(int L){
    drain(cnt);
    fox(l, n){
        if (s[l]=='J') cnt[0]++;
        if (s[l]=='O' && cnt[0]>0){cnt[1]++; cnt[0]--;}
        if (s[l]=='I'){
            if (L>0){cnt[0]++; L--;}
            else if (cnt[1]){cnt[1]--; cnt[2]++;}
            else return 0;
        }
    }
    return 1;
}
int main(){
    cin >> n >> s;
    hi=n;
    while(lo<hi){
        mid=(lo+hi)/2;
        //cout << mid << endl;
        if (check(mid)) hi=mid;
        else lo=mid+1;
    }
    //cout << lo << endl;
    check(lo);
    cout << cnt[2] << endl;
    return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 3916
final_rank: 10

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

#define pb push_back
const int N = 1e6L + 11;
char s[N];
bool vis[N];

bool chk(int n, int m) {
	fill(vis, vis + n + 1, 0);
	vector <int> l, r;
	for(int i = n; i >= 1; i --)
		if(s[i] == 'I' && r.size() < m) {
			r.pb(i);
			vis[i] = 1;
		}
	reverse(r.begin(), r.end());
	for(int i = 1; i <= n; i ++)
		if((s[i] == 'I' || s[i] == 'J') && !vis[i] && l.size() < m)
			l.pb(i);

	if(l.size() < m || r.size() < m) return 0;
	int p = 0;
	for(int i = 1; i <= n; i ++)
		if(s[i] == 'O' && p < m && l[p] <= i && r[p] >= i)
			p ++;
	return p == m;
}

int main() {
	int n; cin >> n;
	scanf("%s", s + 1);
	int l = 0, r = n / 3 + 1;
	while(l + 1 < r) {
		int m = (l + r) / 2;
		if(chk(n, m)) l = m;
		else r = m;
	}
	cout << l << '\n';
}
accuracy: 1
time_ms: 280
memory_kb: 9608
final_rank: 17

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

int main() {
  int N;
  string S;
  cin >> N >> S;

  auto ok = [&](auto k) {
    auto l = 0, m = 0, r = 0;
    for(auto i = N - 1; 0 <= i; --i) {
      if(S[i] == 'J') if(l < m) ++l;
      if(S[i] == 'O') if(m < r) ++m;
      if(S[i] == 'I') {
        if(r < k)      ++r;
        else if(l < m) ++l;
      }
    }
    return l == k;
  };

  auto l = 0, h = N;
  while(l + 1 < h) {
    auto m = (l + h) / 2;
    if(ok(m)) l = m;
    else      h = m;
  }
  cout << l << endl;
}
accuracy: 1
time_ms: 130
memory_kb: 3880
final_rank: 9

code_snippet: #include<bits/stdc++.h>
#define rep(i,n)for(int i=0;i<(n);i++)
using namespace std;

int n, O[1000000], I[1000000], a, b;
char s[1000001];
bool ok(int t) {
	if (a < t || b < t)return 0;
	int p = n;
	rep(i, t) {
		p = min(p - 1, O[i] - 1);
		while (0 <= p && (s[p] == 'O' || (s[p] == 'I'&&p >= I[t - 1])))p--;
		if (p < 0)return 0;
	}
	return 1;
}
int main() {
	scanf("%d%s", &n, s);
	for (int i = n - 1; i >= 0; i--) {
		if (s[i] == 'I')I[a++] = i;
		if (s[i] == 'O'&&b < a)O[b++] = i;
	}
	int l = 0, r = n / 3;
	while (l != r) {
		int t = (l + r) / 2;
		if (r - l == 1)t = r;
		if (ok(t))l = t;
		else r = t - 1;
	}
	printf("%d\n", l);
}
accuracy: 1
time_ms: 100
memory_kb: 7604
final_rank: 13