【题解】StarryCoding P236 更短一点

题目传送门: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} xi1=yi1 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 1t104) - 测试用例数。

接下来的 2 t 2t 2t行包含测试用例–每两行一个。

每个测试用例的第一行包含整数 n n n( 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105) - 字符串 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 0000 S y 1111

其中 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改编而成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值