JOI2013 JOIOI の塔 (Tower of JOIOI)题解

发布时间 2023-07-22 11:06:33作者: 喵仔牛奶

Description

给定一个由 JOI 组成的字符串,求最多能拆分成多少 JOIIOI

对于所有数据,\(1\leq \vert S\vert\leq 10^6\)

Solution

先处理出 \(\text{pre}_i\) 为前缀 JI 的数量,即能组成多少个头部。

然后倒着做,维护当前拼出的 IOI 和最终成品的数量。遇到 JO 就模拟拼接,遇到 I 判断当前的 \(\text{pre}_i\) 是否小于等于 IOI 的总数量,若成立就拼成 IOI,否则作为 I

判断这个是因为 I 可以作为最后的 I 也可以作为开头的 I。若大于等于前缀 JI 数量则作为最后的 I 数量够用,无需继续拼接了。

时间复杂度 \(\mathcal{O}(n)\)

Code

#include <bits/stdc++.h>
using namespace std;
namespace Milkcat {
    const int N = 2e7 + 5;
    int n, ow, w, tot, pre[N]; char s[N];
	int main() {
		cin >> n >> (s + 1);
		for (int i = 1; i <= n; i ++)
			pre[i] = pre[i - 1] + (s[i] == 'J' || s[i] == 'I');
		for (int i = n; i >= 1; i --) {
    		if (s[i] == 'J' && ow) ow --, tot ++;
    		if (s[i] == 'O' && w) w --, ow ++;
			if (s[i] == 'I') {
				if (ow + w >= pre[i] && ow) ow --, tot ++;
				else w ++;
			} 
		}
		cout << tot << '\n';
        return 0;
    }
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
    int T = 1;
    while (T --) Milkcat::main();
    return 0;
}

/*
15
NNOWWOONONWOWWO
*/