CF思维题(cf round 1019 div.2 b题)

发布于:2025-04-23 ⋅ 阅读:(125) ⋅ 点赞:(0)

CF思维题(cf round 1019 div.2 b题)

Problem - B - Codeforces

题目大意:
给出一个 01 01 01字符串,其中字符串的长度是 n ( 1 ≤ n ≤ 2 × 1 0 5 ) n(1 \leq n \leq 2 \times 10^5) n(1n2×105)

现在有两个按钮 0 , 1 0, 1 0,1,开始时手在按钮 0 0 0上。我们每次可以做出两次操作:

  • 按下手上的按钮,输出按钮上面的数字( 0 0 0 1 1 1)
  • 将手上的按钮换成另一个按钮

定义操作次数为:使用上述两种操作,选择其一,输出完整个字符串所需要的操作次数

现在可以改变字符串,我们可以任选两个索引 l , r l, r l,r,并反转子串 S l r S_{lr} Slr,我们就可以在新字符串上操作

问最小操作次数是多少?

解法:

考虑反转字符串的特性:

首先对于反转一个字符串中的子串,只有在反转处会改变连接状态,对于反转位置之前,中间,之后的地方,字符串的连接状态没有改变。例如,对于下面这个字符串,我们想要反转区间 [ L , R ] [L, R] [L,R]

010111... L . . . 0110... R . . . 10011 010111...L...0110...R...10011 010111...L...0110...R...10011

显然,这里的操作次数最多只会减少 2 2 2,原因是反转只改变了反转连接处的连接关系

对于一个字符串来说,我们不妨假设每一个字符串的前面都加上了一个虚开头 0 0 0,这样做的好处不言而喻。对于以 1 1 1开头的字符串,这样操作说明了 0 0 0 1 1 1之间需要发生转换,同时在统计 01 01 01段时方便了后续的思考。读者不妨考虑一下

统计字符串中 01 01 01 10 10 10段的数量

c n t ( 01 ) ≥ 2 ∣ ∣ c n t ( 10 ) ≥ 2 cnt(01) \geq 2 || cnt(10) \geq 2 cnt(01)2∣∣cnt(10)2,我们总是能通过反转使得操作次数减少 2 2 2

我们还要统计字符串需要转换按钮的次数 m m m

若不满足上面条件,但是 m ≥ 2 m \geq 2 m2,我们可以使得操作次数减少 1 1 1

例如 10 10 10 010 010 010

代码如下:

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

void solve() {
	int n;
	string str;
	cin >> n >> str;
	char prev = '0';
	int m = 0, c01 = 0, c10 = 0;
	for (int i = 0; i < str.size(); i ++) {
		char cur = str[i];
		if (cur != prev) {
			m ++;
			if (prev == '0') c01 ++;
			else c10 ++;
		}
		prev = cur;
	}
	int res = n + m;
	if (c01 >= 2 || c10 >= 2) {
		res -= 2;
	} else if (m >= 2) {
		res -= 1;
	}
	cout << res << endl;
}

int main() {
	int t;
	cin >> t;
	while (t --) {
		solve();
	}
	return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到