2025年CSP-X复赛真题及题解(山东):T2IOI串
2025年CSP-X复赛真题及题解(山东):T2IOI串
题目描述
小明对字符串 IOI 怀有特殊的感情,他定义一种由大写英文字母 I 和 O 构成的字符串为“好串”,当且仅当它可以被划分为三个非空部分,依次为:
第一部分:连续若干个 I
第二部分:连续若干个 O
第三部分:连续若干个 I
如:
IIIOOIIII 是一个好串,IOI 也是一个好串;
OIOI,IIO 都不是好串。
现在,小明有一个长度为 n n n 的字符串 S S S,且 S S S 仅包含字符 I 和 O。
他可以进行任意次修改操作,每一次操作可将字符串中某一个位置的字符替换成另一个字符(即把 I 改为 O,或把 O 改为 I)。
例如:
当 S = I I I O O O I O O I I S = \tt{IIIOOOIOOII} S=IIIOOOIOOII 时,根据上述定义, S S S 不是一个“好串”,但小明可以有多种方法通过修改操作把 S S S 变为“好串”:
方法 1:把第 7 个字符 I 改为 O,经过 1 次操作得到 IIIOOOOOOII;
方法 2:分别把第 8 个和第 9 个字符 O 改为 I,经过 2 次操作得到 IIIOOOIIIII。
可以确定,至少经过 1 次修改操作才能把上面的字符串 S S S 变为“好串”。
你的任务:
告诉你小明的字符串 S S S,请你帮小明计算,至少需要进行多少次修改操作,才能将字符串 S S S 变为一个“好串”。如果 S S S 已经是一个“好串”,输出 0 0 0。
输入格式
一行,仅由 I 和 O 两种字符组成的字符串 S S S。
输出格式
一行,包含一个整数,表示把字符串 S S S 修改为“好串”需要的最少的修改次数。
输入输出样例 1
输入 1
IIIOOOIOOII
输出 1
1
输入输出样例 2
输入 2
IOOIOOIOOOII
输出 2
2
【数据范围】
对于所有的数据,字符串的长度 n n n 满足 3 ≤ n ≤ 5 × 1 0 3 3 \le n \le 5 \times 10^3 3≤n≤5×103,且字符串中仅包含大写英文字母 I 和 O。
| 测试点 | n ≤ n \le n≤ | 特殊性质 |
|---|---|---|
| 1 1 1 | 1000 1000 1000 | 字符全部为 I |
| 2 2 2 | 1000 1000 1000 | 字符全部为 O |
| 3 ∼ 13 3\sim 13 3∼13 | 200 200 200 | 无 |
| 14 ∼ 20 14\sim 20 14∼20 | 5 × 1 0 3 5 \times 10^3 5×103 | 无 |
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+10; // 定义最大字符串长度
string s;
int sumI[N],sumO[N]; // 前缀和数组:sumI[i]表示前i个字符中'I'的数量int main(){cin>>s; // 输入字符串int n=s.size(); // 获取字符串长度// 构建前缀和数组,索引从1开始for(int i=1;i<=n;i++){// 如果下标i-1的字符是'I',sumI[i] = sumI[i-1] + 1,否则不变sumI[i]=sumI[i-1]+(s[i-1]=='I');// 如果下标i-1的字符是'O',sumO[i] = sumO[i-1] + 1,否则不变 sumO[i]=sumO[i-1]+(s[i-1]=='O');}int ans=n; // 初始化答案为最坏情况(需要修改所有字符)int cnt; // 临时变量,记录当前划分的修改次数// 枚举所有可能的三段划分方式:// 第一段:[第1, 第i] - 连续I// 第二段:[第i+1, 第j] - 连续O // 第三段:[第j+1, 第n] - 连续Ifor(int i=1;i<=n-2;i++){ // i: 第一段结束位置(保证后面至少还有2个字符)for(int j=i+1;j<=n-1;j++){ // j: 第二段结束位置(保证后面至少还有1个字符)// 计算将当前划分变为好串所需的修改次数:cnt = sumO[i] + // 第一段中所有'O'要改为'I'(sumI[j]-sumI[i]) + // 第二段中所有'I'要改为'O' (sumO[n]-sumO[j]); // 第三段中所有'O'要改为'I'ans=min(ans,cnt); // 更新最小修改次数}}cout<<ans; // 输出结果return 0;
}
算法思路
-
问题理解:好串要求形如
I...IO...OI...I,即三段结构 -
前缀和预处理:
sumI[i]:前i个字符中’I’的数量sumO[i]:前i个字符中’O’的数量
-
枚举所有划分:
- 对于每个可能的划分点(i,j),计算将字符串变为对应三段结构所需的修改次数
- 修改次数 = 第一段中’O’的数量 + 第二段中’I’的数量 + 第三段中’O’的数量
-
时间复杂度:O(n²),对于n≤5000可以接受
文末福利:《csp信奥赛12大高频考点专题集训》
https://edu.csdn.net/course/detail/40437 点击跳转到秘籍

更多csp信奥赛c++完整系列课程,点击查看老师的个人主页:
https://edu.csdn.net/lecturer/7901 点击链接

#include<bits/stdc++.h>
using namespace std;
int main(){cout<<"############# 祝看到这篇秘籍的OIer: ###############";cout<<"#### AC不是偶然,一等奖是必然!祝你AK全场! ########";cout<<"############# 复赛夺魁,一等在手! #################";return 0;
}
