The 2022 ICPC Asia Regionals Online Contest - A 01 Sequence

11 篇文章 0 订阅
4 篇文章 0 订阅

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 rili+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=3lencount(1)=3RL+1count(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));
	}
}

By-Round Moon

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Round moon

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

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

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

打赏作者

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

抵扣说明:

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

余额充值