[Daimayuan] 非递减的01序列(C++,前缀和)

题面

h u a j i huaji huaji有一个 01 序列,每次可以对其中的某一位取反( 0 0 0 1 1 1 1 1 1 0 0 0

求最少翻转其中的几位可以使得该序列变为非递减序列

输入格式

第一行输入一个整数 n n n ( 1 ≤ n ≤ 1 0 6 1≤n≤10^6 1n106)

第二行输入一个长度为 n n n 的且仅包含 01 的字符串

输出格式

输出一个整数,为该序列变为非递减序列的最少操作次数

输入样例
6
010110
输出样例
2
解题思路

其实题意描述有一点问题,求的应该是将该序列变为单调不减的01序列(因为没有单调性其实也是非递减)。

我们的目标具体来说就是选定某个位置,之前的均为0,之后的均为1,同时保证与原序列相似性最高。

根据这个目标,我们只需要遍历每一个可能的位置,选出其中需要操作次数最少的就可以了。

问题在于如何快速获取操作次数。

因为只有两种元素:0和1。所以我们只需要知道其中一种的数量,剩下的都是另外一种。

那么采用前缀和的概念,累计指定位置前 0 0 0的数量。

//首元素特殊处理
if (str[0] == '0') zero_counter[0] = 1;
else one_counter[0] = 1;

for (int i = 1; i < len; i++) {
	zero_counter[i] = zero_counter[i - 1];
	if (str[i] == '0') zero_counter[i]++;
}

然后遍历每一个位置即可:

int ans = zero_counter[len - 1];//目标序列没有0
for (int i = 0; i < len; i++) {
	ans = min(ans, (i + 1 - zero_counter[i]) + (zero_counter[len - 1] - zero_counter[i]));
}

最后,AC代码如下:

#include <iostream>
using namespace std;
const int max_len = 1e6;

int zero_counter[max_len];

int main() {
	int n;
	cin >> n;
	string str;
	cin >> str;
	int len = str.size();
	if (str[0] == '0') zero_counter[0] = 1;
	for (int i = 1; i < len; i++) {
		zero_counter[i] = zero_counter[i - 1];
		if (str[i] == '0') zero_counter[i]++;
	}
	int ans = zero_counter[len - 1];//目标序列没有0
	for (int i = 0; i < len; i++) {
		ans = min(ans, (i + 1 - zero_counter[i]) + (zero_counter[len - 1] - zero_counter[i]));
	}
	cout << ans << endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WitheredSakura_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值