2022ICPC网络赛第一场-A 01 Sequence

Given a binary cyclic sequence S of length n, whose elements are either 0 or 1, you can do the following operation any number of times.

  • Operation: if the length of S is greater than or equal to 3, choose a position i (1≤i≤n) such that Si​=1, remove the element on position i and both its adjacent elements (remove 3 elements in total), and do not change the relative order of the other elements. Note that elements in the first and last positions are considered adjacent.

A binary cyclic sequence S is called good if you can make S empty using the operation above.

And the beauty of a binary cyclic sequence S, f(S), is defined as the minimum number of modifications needed to make S good. In a single modification you can flip an arbitrary element in S, that is, 0 becomes 1 and 1 becomes 0.

Given are a binary string a of length n and q queries. For the i-th query you are given two integers li​ and ri​, and you should answer f(ali​..ri​​) (where we consider the substring ali​..ri​​ as a cyclic sequence).

题意

        给定01字符串S

  • 如果S[i]是1,那么就可以删掉它以及与它相邻的两个字符
  • 可以f通过反转将一个字符 从0变1或从1变0

问:我们需要反转几次才可以删掉字符串S

当字符串长度为3时,1个1就可以删除

字符串长度为6时,至少两个不连续的1才可以删除

字符串长度为n时,至少需要n/3个不连续的1才可以删除

当不连续1的个数不足n/3时,就需要进行反转

所以这道题需要求的是字符串S中有多少个不连续的1

当有n个1连续时,最多有(n+1)/3个1有效

例如 011111    我们可以把它当成  010101  其中1的个数>n/3,所以不需要反转就可以删除

我们可以把一个01字符串S分成两部分,先求左右两端连续1的个数之和,算出有效1的个数

再算中间不连续1的个数

如果中间+两端有效1的个数不足n/3,那么就需要再进行反转

代码

#include <iostream>
using namespace std;
const int Maxn = 1000010;
int R[Maxn];
int L[Maxn];
int sum[Maxn];
int n, q, l, r, ans = 0;
string str;

void init() {
    //sum[i]代表前i个字符 不连续1的个数
	sum[1] = str[1] == '1' ? 1 : 0;
	for (int i = 2; i < str.size(); i++) {
		if (str[i] == '1') {
			sum[i] = sum[i - 2] + 1;
		} else {
			sum[i] = sum[i - 1];
		}
	}
    //L[i]代表第i个字符结尾,左边连续1的个数
	for (int i = 1; i < str.size(); i++) {
		if (str[i] == '1') {
			L[i] = L[i - 1] + 1;
		} else {
			L[i] = 0;
		}
	}
    //R[i]代表第i个字符结尾,右边连续1的个数
	for (int i = str.size() - 1; i > 0; i--) {
		if (str[i] == '1') {
			R[i] = R[i + 1] + 1;
		} else {
			R[i] = 0;
		}
	}
}

int main() {
	cin >> n >> q >> str;
	str = " " + str;
	init();
	while (n--) {
		cin >> l >> r;
		int cnt = L[r] + R[l]; //两端连续1的个数
        //ans是不连续1的个数,cnt个连续的1最多有(cnt+1)/2个1有效	            
        ans = sum[r - L[r]] - sum[l + R[l]] + (cnt + 1) / 2;
        
        //ans*3>=(r-l+1)
		if (ans >= (r - l + 1) / 3) {
			cout << "0\n";
		} else {
			cout << (r - l + 1) / 3 - ans << "\n";
		}
	}
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值