题面
| Good Egg Galaxy — Koji Kondo, Super Mario Galaxy |
|---|
![]() |
|---|
Let be a positive integer. Mario has a binary string of length . In one move, he can choose any position () such that it’s between two 1’s, i.e., , and then set to either 0 or 1.
Mario can perform this operation as many times as he wants (possibly zero). What’s the minimum and maximum number of 1’s that can be in the resulting string?
A binary string is a string whose characters are either 0 or 1.
Input
Each test contains multiple test cases. The first line contains the number of test cases (). The description of the test cases follows.
The first line of each test case contains an integer () — the length of the string.
The second line of each test case contains a string of length consisting of characters 0 or 1.
Output
For each test case, output two integers — the minimum and maximum number of 1’s in the resulting string after some number of moves.
思路
这题的操作是:选中一个中间位置 ,要求左右都是 ,然后把 改成 或
核心要分开算 和
1. 最大值
要让 尽量多,只需要考虑把可变的 变成
一个位置能从 变成 的条件是它当前形态为 (即中间是 ,两边是 )
因此:
- 先统计初始 的数量
- 再统计满足 的位置数
线性扫描一遍即可
2. 最小值
要让 尽量少,需要做一些 的操作(中心在 )
关键观察: 可以看成分隔符。把字符串按 切成若干段后,每段可以独立计算最小贡献,再求和
WARNING为什么按
00分段?因为题目要求的可以更改的地方是在两个1之间,而如果出现了
00,这两个元素不满足任何更改的条件(相邻有0)
对每一段 :
- 找到这段最左侧的 :
- 找到这段最右侧的 :
- 如果这段没有 ,贡献为 ;否则令这一段最少能保留的 数量为:
于是整题的最小值是所有分段贡献之和:
最后求出结果,输出
代码
#include <bits/stdc++.h>
using namespace std;
int main() { int t; cin >> t; while (t --) { int n; string s; cin >> n >> s; int c = 0; for (char ch : s) { c += (ch == '1'); }
int mx = c; for (int i = 1; i + 1 < n; ++i) { if (s[i] == '0' && s[i - 1] == '1' && s[i + 1] == '1') { mx ++; } }
int mn = 0; int i = 0; while (i < n) { int l = i; int r = i;
while (r + 1 < n && !(s[r] == '0' && s[r + 1] == '0')) { r ++; }
int first1 = -1, last1 = -1; for (int j = l; j <= r; j ++) { if (s[j] == '1') { if (first1 == -1) first1 = j; last1 = j; } }
if (first1 != -1) { int len = last1 - first1 + 1; mn += len / 2 + 1; }
i = r + 1; }
cout << mn << ' ' << mx << '\n'; }}
