题目传送门:P236 更短一点 | StarryCoding算法竞赛平台
题目描述
小小的也很可爱呢…
P i p e r Piper Piper有一串长度为 n n n的二进制字符串 s s s(即字符串只由 0 0 0和 1 1 1组成)。 P i p e r Piper Piper觉得这串字符串不可爱,他想让它变得更可爱一点,但同时又希望它可爱地有内涵一点,所以 P i p e r Piper Piper决定用一种特殊的方式让它变得可爱。
选择两个连续的字符 s i s_i si和 s i + 1 s_{i+1} si+1,如果 s i s_i si是1, s i + 1 s_{i + 1} si+1是0,他就可以擦除其中的1个字符(他可以选择擦除哪一个,但不能同时擦除两个字符)。擦除后字符串会更加地可爱!。
P i p e r Piper Piper可以进行任意数量的擦除(可能是零),他想让字符串 s s s尽可能可爱。他认为对于两个不同的字符串 x x x和 y y y,短的字符串更可爱,如果它们的长度相同,那么从词典上看更小的字符串更可爱。
小提示:如果我们有两个长度相同的字符串 x x x和 y y y,那么如果有一个位置 i i i是 x 1 = y 1 x_1 = y_1 x1=y1、 x 2 = y 2 x_2 = y_2 x2=y2、…、 x i − 1 = y i − 1 x_{i - 1} = y_{i - 1} xi−1=yi−1和 x i < y i x_i \lt y_i xi<yi,那么 x x x在词法上比 y y y小。
请打印 P i p e r Piper Piper在操作过后能得到的最可爱的字符串。
输入描述
第一行包含整数 t t t( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104) - 测试用例数。
接下来的 2 t 2t 2t行包含测试用例–每两行一个。
每个测试用例的第一行包含整数 n n n( 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1≤n≤105) - 字符串 s s s的长度。
第二行包含二进制字符串 s s s。字符串 s s s是长度为 n n n的字符串,仅由 0 和 1 组成。
保证测试用例中 n n n的总和不超过 1 0 5 10^5 105。
输出描述
打印 t t t个答案–每个测试用例一个。
i i i-th 测试用例的答案是李在做了一定数量的操作(可能是零)后能得到的最可爱的字符串。
输入样例1
5
10
0001111111
4
0101
8
11001101
10
1110000000
1
1
输出样例1
0001111111
001
01
0
1
样例解释
在第一个测试用例中, P i p e r Piper Piper不用执行任何动作。
在第二个测试用例中, P i p e r Piper Piper应该擦除 s 2 s_2 s2 。
例如,在第三个测试用例中, P i p e r Piper Piper可以按照以下顺序下棋:11001101 → \rightarrow → 1100101 → \rightarrow → 110101 → \rightarrow → 10101 → \rightarrow → 1101 → \rightarrow → 101 → \rightarrow → 01。
思路
已知我们无法对非降序的字符串进行操作。
操作的条件:前1后0。所以猜想:对于一串以1开头,以0结尾的子串都可以被擦除至剩一个0。
证明:
对于一串以1开头的字符串,从前往后删0,我们总能得到一串不包含0的字符串,这很容易。现在保留末尾的0,再从后往前删掉所有的1。显然是可取的。
于是我们得到结论,对于一串以1开头,以0结尾的子串都可以被擦除至剩一个0。而由于我们无法对非降序的字符串进行操作,所以答案的构成我们可以视作:
00 … 00 ⏟ x S 11 … 11 ⏟ y \underbrace{00 \ldots 00}_{x} \space S \space \underbrace{11 \ldots 11}_{y} x 00…00 S y 11…11
其中 S S S为一串以1开头,以0结尾的子串。必然是这样的,如果在最前面加上一个1,那么不妨把中间子串的左边界扩至开头来保持结构;在末尾加0也是同理。
于是我们只要找第一个1,再找末尾一个0,将这两个位置及其中间的字符都替换为0即可。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 9;
void solve()
{
int n; cin >> n;
string s; cin >> s;
int l = -1, r = -1;
int flag = 1;
for(int i = 0; i < n; ++i)
{
if(s[i] == '1' && flag)
{
l = i;
flag = 0;
}
if(s[i] == '0' && !flag)
{
r = i;
}
}
if(l != -1 && r != -1)
{
for(int i = 0; i < l; ++i) cout << s[i];
for(int i = r; i < n; ++i) cout << s[i];
cout << '\n';
}
else cout << s << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
while(_ --)solve();
return 0;
}
本题由codeforces上的1369B改编而成