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";
}
}
}