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 S i S_{i} 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 l i l_{i} li and r i r_{i} ri, and you should answer f( a l i . . r i a_ {l_{i}..r_{i}} ali..ri) (where we consider the substring a l i . . r i a_ {l_{i}..r_{i}} ali..ri as a cyclic sequence).
输入描述
The first line contains two integers n and q (3≤n≤106, 1≤q≤106) — the length of string a and the number of queries, respectively.
The second line contains the string a 1 a 2 . . . a n a_{1}a_{2}...a_{n} a1a2...an, where each a i is either 0 or 1.Each of the following q lines contains two integers l i l_{i} li and r i r_{i} ri (1 ≤ l i l_{i} li ≤ r i r_{i} ri≤ n, ( r i − l i + 1 ≡ r_{i} - l_{i}+1\equiv ri−li+1≡ 0 mod 3) describing the i-th query.
输出描述
Output q lines, where the i-th line contains a single integer — the answer for the i-th query.
Sample Input1
7 7
1000011
1 3
2 4
3 5
4 6
5 7
1 6
2 7
Sample Output1
0
1
1
0
0
1
1
Sample Input2
12 1
110110110000
1 12
Sample Output2
1
Sample Input3
20 10
00001000100000010000
18 20
14 16
7 12
2 10
16 18
6 20
8 10
13 15
1 6
1 12
Sample Output3
1
0
1
1
0
3
0
1
1
2
Hint
代码长度限制
16 KB
时间限制
2000 ms
内存限制
512 MB
题解
题目大意
有一个只含有01的序列,现如今截取其中一段首位连接成环。规定此子序列的长度须为3的倍数,且长度不为0。
- 有如下两个操作将0变为1.
- 将位置为1的元素左侧及右侧共三个元素去除,并愈合该环。
目标是询问这个序列最少执行多少次的0成1的操作可以将该环全部删除。
题目分析
首先我们肯定是删除1的位置左右无1最优,那么如果有怎么办呢,我们可以发现如果连续的一,每两个可以看成一个可以起删除作用的1也就是说第二个1和0是没有任何区别的。那么也就是说我们需要去寻找,多少个可以起真正删除作用的1。
我们如果知道了起删除作用的1有x个,那么我们可以由公式得到结果
a n s = l e n − c o u n t ′ ( 1 ) 3 = R − L + 1 − c o u n t ′ ( 1 ) 3 ans=\frac{len-count'(1)}{3} =\frac{R-L+1-count'(1)}{3} ans=3len−count′(1)=3R−L+1−count′(1)
len的值可以由O(1)得到,现在我们在想如何查询真正起作用的1的个数呢?
博主这里采用了线段树的方法。
线段树构造
我们可以想到如果连续的1,其有效的数量是 ⌈ \lceil ⌈ n 2 \frac{n}{2} 2n ⌉ \rceil ⌉,这里n是连续1的个数。那么我们考虑线段树,用线段树的优化不就是在于可以选择其中一段而这一段恰巧在范围内,可以省去很多计算吗?那我们记录左侧的连续1的数量和右侧连续1的数量。这样我们就可以模拟出任何区间的组合搭配了。那么我们还需要计算结果,结果其实就是左右两个区间的数量重组在一起的结果。因为需要考虑到有没有又一边的范围全部都是1,所以我们还需要记录len(当前区间的长度)。如果当前区间长度正好等于其中l或者r的数量那么我们就知道这是一种全是1的情况。而对于全是1的时候我们尤其要注意我们的l和r怎么变化。
可能有的伙伴们问这不是环吗?也没见博主处理环呀。
其实是有的,我们这里求出来的是不成环的可删1的数量。那么我们算出来后只需要看我们的查询区间的结果里,l和r的数量,然后将他俩重组即可得到最终正确的结果。
Accepted Code
//#include<unordered_map>
#include<functional>
#include<algorithm>
#include<iostream>
#include<string.h>
#include <iomanip>
#include<stdio.h>
#include<vector>
#include<string>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll ll_inf = 9223372036854775807;
const int int_inf = 2147483647;
const short short_inf = 32767;
const ll less_inf = 0x3f3f3f3f;
const char char_inf = 127;
#pragma GCC optimize(2)
#define accelerate cin.tie(NULL);cout.tie(NULL);ios::sync_with_stdio(false)
#define outl(info) out(info);puts("")
#define PI 3.141592653589793
#define EPS 1.0e-8
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
inline ll read() {
ll c = getchar(), Nig = 1, x = 0;
while (!isdigit(c) && c != '-')c = getchar();
if (c == '-')Nig = -1, c = getchar();
while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
return Nig * x;
}
inline void out(ll a) {
if (a < 0)putchar('-'), a = -a;
if (a > 9)out(a / 10);
putchar(a % 10 + '0');
}
inline void print(ll a, char end = '\n') {
out(a); putchar(end); }
ll qpow(ll x, ll n, ll mod) {
ll res = 1;
while (n > 0) {
if (n & 1)res = (res * x) % mod;
x = (x * x) % mod;
n >>= 1;
}
return res;
}
#define read read()
const int N = 1000005;
struct node
{
int num;
int l, r, len;
}tree[N << 2];
char save[N];
void push_up(int rt)
{
tree[rt].len = tree[rt << 1].len + tree[rt << 1 | 1].len;
bool sw1 = false, sw2 = false;
if (tree[rt << 1].l && tree[rt << 1].l == tree[rt << 1].len)sw1 = true;
if (tree[rt << 1 | 1].l && tree[rt << 1 | 1].l == tree[rt << 1 | 1].len)sw2 = true;
if (sw1 && sw2)
{
tree[rt].l = tree[rt].r = tree[rt << 1].r + tree[rt << 1 | 1].l;
tree[rt].num = ceil(tree[rt].l / 2.0);
}
else
{
if (sw1)
{
tree[rt].l = tree[rt << 1].r + tree[rt << 1 | 1].l;
tree[rt].r = tree[rt << 1 | 1].r;
tree[rt].num = tree[rt << 1 | 1].num - ceil(tree[rt << 1 | 1].l / 2.0) + ceil((tree[rt << 1].r + tree[rt << 1 | 1].l) / 2.0);
}
else if (sw2)
{
tree[rt].r = tree[rt << 1 | 1].r + tree[rt << 1].r;
tree[rt].l = tree[rt << 1].l;
tree[rt].num = tree[rt << 1].num - ceil(tree[rt << 1].r / 2.0) + ceil((tree[rt << 1 | 1].l + tree[rt << 1].r) / 2.0);
}
else
{
tree[rt].l = tree[rt << 1].l;
tree[rt].r = tree[rt << 1 | 1].r;
tree[rt].num = tree[rt << 1].num + tree[rt << 1 | 1].num - ceil(tree[rt << 1].r / 2.0) - ceil(tree[rt << 1 | 1].l / 2.0) + ceil((tree[rt << 1 | 1].l + tree[rt << 1].r) / 2.0);
}
}
}
void creat(int l, int r, int rt)
{
if (l == r)
{
tree[rt].l = tree[rt].r = (save[l] == '1' ? 1 : 0);
tree[rt].num = tree[rt].l ? 1 : 0;
tree[rt].len = 1;
return;
}
int mid = l + r >> 1;
creat(l, mid, rt << 1);
creat(mid + 1, r, rt << 1 | 1);
push_up(rt);
}
node query(int L, int R, int l, int r, int rt)
{
if (L <= l && r <= R) return tree[rt];
node temp1 = node{
-1,-1,-1 ,-1 }, temp2 = node{
-1,-1,-1 ,-1 };
int mid = l + r >> 1;
if (L <= mid) temp1 = query(L, R, l, mid, rt << 1);
if (R >= mid + 1) temp2 = query(L, R, mid + 1, r, rt << 1 | 1);
if (~temp1.num && ~temp2.num)
{
node res;
res.len = temp1.len + temp2.len;
bool sw1 = false, sw2 = false;
if (temp1.l && temp1.l == temp1.len)sw1 = true;
if (temp2.l && temp2.l == temp2.len)sw2 = true;
if (sw1 && sw2)
{
res.l = res.r = temp1.r + temp2.l;
res.num = ceil(res.l / 2.0);
}
else
{
if (sw1)
{
res.l = temp1.r + temp2.l;
res.r = temp2.r;
res.num = temp2.num - ceil(temp2.l / 2.0) + ceil((temp1.r + temp2.l) / 2.0);
}
else if (sw2)
{
res.l = temp1.l;
res.r = temp1.r + temp2.l;
res.num = temp1.num - ceil(temp1.r / 2.0) + ceil((temp1.r + temp2.l) / 2.0);
}
else
{
res.l = temp1.l;
res.r = temp2.r;
res.num = temp1.num + temp2.num - ceil(temp1.r / 2.0) - ceil(temp2.l / 2.0) + ceil((temp1.r + temp2.l) / 2.0);
}
}
return res;
}
else if (~temp1.num)return temp1;
else return temp2;
}
int main()
{
int n = read, k = read;
scanf("%s", save + 1);
creat(1, n, 1);
while (k--)
{
int L = read, R = read;
node res = query(L, R, 1, n, 1);
res.num = res.num - ceil(res.l / 2.0) - ceil(res.r / 2.0) + ceil((res.l + res.r) / 2.0);
print(max(0, (R - L + 1 - res.num * 3) / 3));
}
}