[JOI 2013 Final]JOIOI 塔

[JOI 2013 Final]JOIOI 塔

题意

给出一个由 JOI 组成的字符串,可从中取出一些子序列。

求最多取出多少 IOIJOI

思路

若答案 x 可行,则所有 y<x 均可行,

若答案 x 不可行,则所有 y>x 均不可行。

这样就可以可行性二分。

考虑如何判断答案 x 是否可行。

JOIIOI 都有 OI

发现 J 只能用来拼 JOI 的第一位,O 只能用来拼 OI

而问题就在于 I,既可以用来做 IOI 的第一位,也可以用来拼 I

从后往前扫描字符串,同时维护 I,O,J,OI,JOI,IOI 的个数。

如果扫到 J,O,将对应的个数加一,如果可以就拼接成为 JOI,OI

对于 I,我们需要的 OI 只有 x 个,若当前拼出的 OI 总数小于 x,就拼 OI,否则和 OI 拼接出 IOI

如果最后的 JOI,IOI 总数大于等于 x 则可行。

代码

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

const int N = 1e6 + 5;

int n;
char S[N];

bool check(int x) {
	int JOI = 0, IOI = 0, OI = 0;
	int J = 0, O = 0, I = 0;
	for (int i = n; i >= 1; i --) {
		if (S[i] == 'I') {
			I ++;
			if (OI + JOI + IOI + I - 1 >= x && OI > 0) {
				I --;
				OI --;
				IOI ++;
			}
		}
		if (S[i] == 'O') {
			O ++;
			if (I > 0 && O > 0) {
				O --;
				I --;
				OI ++;
			}
		}
		if (S[i] == 'J') {
			J ++;
			if (J > 0 && OI > 0) {
				J --;
				OI --;
				JOI ++;
			}
		}
	}
	return JOI + IOI >= x;
}

int main() {
freopen("joi.in","r",stdin);
freopen("joi.out","w",stdout);
	scanf("%d", &n);
	scanf("%s", S + 1);
	
	int l = 0, r = n, mid, res;
	
	while (l <= r) {
		mid = (l + r) >> 1;
		if (check(mid)) {
			res = mid;
			l = mid + 1;
		} else {
			r = mid - 1;
		}
	} 
	
	cout << res << "\n";
	return 0;
}
posted @   maniubi  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示