codeforces 题目 Kirk and a Binary String (hard version)

题目链接:Problem - D2 - Codeforces

题目:

题目描述:

给你一串 01字符串 s ,你是否能找到一个 01字符串 t ,使得达到两个目标:

① t 串与 s 串在任意 l 和 r 区间内(1\leq l \leq r \leq n)区间位置的最长非递减子序列(前 0 后 1 )的长度与是一样的

② t 串要拥有尽可能多的 0 

思路:

不难想到如果 t 串就是 s 串本身的就能很好的满足目标 ①

但是为了目标 ② ,我们要尽可能的把部分 1 转化成 0 ,但又不改变所有区间的最长非递减子序列长度

我们怎么才能讲所有区间考虑完全?我们可以从后往前遍历,精准探讨每一个位置作为左区间的情况下去广泛分析有区间的情况。遍历到 0 自然不用动,当我们遍历到 1 的时候, 什么情况下我们可以把这个 1 变成 0 ?当且仅当后面的 1 个数等于 0 的个数的时候才可以,因为在这种情况下:

①要么是位于最后,后面什么都没有

②要么是后面的串中 1 都在 0 前面,且二者个数相等(之前已经转变的位置不考虑不在内,之后解释)

所以在这个时候,会达成一种平衡状态,即,无论我这个位置是 1 还是 0 ,这个位置以及右侧的最长非递减子序列都一样长。

由图可见,你将 1 转变为 0 不会影响这个位置右侧的最长非递减子序列。并且转变之后,这个位置以及其右半部分的区域我们就可以扔掉不讨论了,因为无论在此之前前面的最后一位是 1 还是  0 ,后面的最长非递减子序列都是一样长的。(神奇吧)

所以我们现在只用从后往前遍历,如果当前后面 1 和 0 个数相等的时候(之前的转换位置不统计)再遇见 1 就可以把这个 1 转换为 0 

思路有了,具体操作请看AC代码

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e5 + 5;

char b[N];

int main()
{
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	string a;
	cin >> a;

	int n = a.size();
	int cnt = 0;

	for (int i = n - 1; i >= 0; i--)
	{
		if (a[i] == '0')
		{
			cnt++;
			b[i] = '0';
		}
		else if (cnt)
		{
			cnt--;
			b[i] = '1';
		}
		else
		    b[i] = '0';
	}

	for (int i = 0; i <= n - 1; i++)
		cout << b[i];

	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值