714 字
4 分钟
1-1

题面#

Good Egg Galaxy — Koji Kondo, Super Mario Galaxy

Let nn be a positive integer. Mario has a binary string ^{\text{∗}} ss of length nn. In one move, he can choose any position ii (2in12 \leq i \leq n-1) such that it’s between two 1’s, i.e., si1=si+1=1s_{i-1} = s_{i+1} = \texttt{1}, and then set sis_i 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?

^{\text{∗}} 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 tt (1t5001 \le t \le 500). The description of the test cases follows.

The first line of each test case contains an integer nn (3n1003 \leq n \leq 100) — the length of the string.

The second line of each test case contains a string ss of length nn 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.

思路#

这题的操作是:选中一个中间位置 ii,要求左右都是 11,然后把 sis_i 改成 0011

核心要分开算 max\mathrm{max}min\mathrm{min}

1. 最大值 max\mathrm{max}#

要让 11 尽量多,只需要考虑把可变的 00 变成 11

一个位置能从 00 变成 11 的条件是它当前形态为 101\texttt{101}(即中间是 00,两边是 11

因此:

  • 先统计初始 11 的数量 c\mathrm{c}
  • 再统计满足 si1=1, si=0, si+1=1s_{i-1}=1,\ s_i=0,\ s_{i+1}=1 的位置数 d\mathrm{d}
  • max=c+d\mathrm{max}=\mathrm{c}+\mathrm{d}

线性扫描一遍即可

2. 最小值 min\mathrm{min}#

要让 11 尽量少,需要做一些 101 \to 0 的操作(中心在 111\texttt{111}

关键观察:00\texttt{00} 可以看成分隔符。把字符串按 00\texttt{00} 切成若干段后,每段可以独立计算最小贡献,再求和

WARNING

为什么按 00 分段?

因为题目要求的可以更改的地方是在两个1之间,而如果出现了00,这两个元素不满足任何更改的条件(相邻有0)

对每一段 [l,r][l, r]

  • 找到这段最左侧的 11first1\mathrm{first1}
  • 找到这段最右侧的 11last1\mathrm{last1}
  • 如果这段没有 11,贡献为 00;否则令这一段最少能保留的 11 数量为:
len=last1first1+1\mathrm{len}=\mathrm{last1}-\mathrm{first1}+1

于是整题的最小值是所有分段贡献之和:

len2+1\left\lfloor \frac{\mathrm{len}}{2}\right\rfloor + 1

最后求出结果,输出

代码#

#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';
}
}
1-1
https://github.com/posts/1-1/
作者
FZSGBall
发布于
2026-04-17
许可协议
CC BY-NC-SA 4.0