CF1504B Flip the Bits 题解

赛时调了半天没调出来,赛后又调了半天还发帖询问后才过的。。。

题意

给定两个 0101a,ba,b,定义操作规则:

对于一个 0101 串,每次只能选择串中从 1i1\sim i 的数字进行翻转(00111100),而且这 ii 个数字 00 的个数与 11 的个数是相同的。

问你能否对 aa 操作后变成 bb

思路

这题我是从后往前考虑的。

结论:从后往前扫,如果碰到 ai=bia_i=b_iai1bi1a_{i-1} \neq b_{i-1} 则就必须将 1i11\sim i-1 翻转。易知此时 1i11\sim i-100 的个数不等于 11 的个数则输出NO\texttt{NO}。如果坚持到底的话,就输出YES\texttt{YES}

感性理解:找到从右到左满足 ai=bia_i=b_i 并且 ai1bi1a_{i-1} \neq b_{i-1} 的第一个 ii,任意取一数 j(i<jn)j(i<j\leq n)。那么我们将 1j11\sim j-1 翻转后,此时 ij1i\sim j-1 就不满足了,所以还要再翻转一次,就跟只翻转 1i11\sim i - 1 一样了。

实现

很明显我们每一次对 1i11\sim i-1 进行翻转操作时,不能直接模拟,否则时间卡爆你。那么怎么优化呢?

考虑到这是一个 0101 串,所以翻转结果只跟翻转次数有关,而且这里的操作是对一个连续的区间考虑的,所以完全可以用树状数组来写(类似于树状数组 2),然后正常写就可以了。

Tip:多组数据时,树状数组清空不能用 memset,否则会 T。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <bits/stdc++.h>
using namespace std;

const int N = 3e5 + 5;

int T, n;
int s[N];

string a1, b1;
int a[N], b[N];

int sum[N << 2];
int lowbit (int x) {
return x & (-x);
}

void update (int x, int y) {//树状数组
while (x <= n) {
sum[x] += y;
x += lowbit(x);
}
return ;
}

int query (int x) {
int res = 0;
while (x != 0) {
res += sum[x];
x -= lowbit(x);
}
return res;
}

int main() {
cin >> T;
while (T--) {
cin >> n >> a1 >> b1;
s[0] = 0;
for (int i = 1; i <= n; ++i) a[i] = a1[i - 1] - '0', b[i] = b1[i - 1] - '0', s[i] = s[i - 1] + a[i];//求前缀1的个数
for (int i = 1; i <= n; ++i) sum[i] = 0;
bool flag = true;
for (int i = n; i >= 1; --i) {
int k = query(i);
if (k % 2 == 1) {
a[i] ^= 1;
}
if (a[i] == b[i]) continue ;
if (s[i] != i - s[i]) { flag = false; break ; }//如果不能进行翻转,就退出
update(1, 1), update(i, -1);//对1~i-1 全部加上1
s[i - 1] = i - 1 - s[i - 1];//前缀1变化
}
puts(flag == true ? "YES" : "NO");
}
return 0;
}

时间复杂度:O(nlogn)O(n\log n)

能过。

Upd on 2021.4.10\text{Upd on 2021.4.10}

这种思路可以 O(n)O(n) 写,而且 nlognn\log n 的写法貌似复杂了(

定义一个计数器 kk 当这个时候需要翻转时就将 k+1k+1,那么每次遍历到时,kk 就是次数。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <bits/stdc++.h>
using namespace std;

const int N = 3e5 + 5;

int T, n;
int s[N];

string a1, b1;
int a[N], b[N];

int main() {
cin >> T;
while (T--) {
cin >> n >> a1 >> b1;
s[0] = 0;
for (int i = 1; i <= n; ++i) a[i] = a1[i - 1] - '0', b[i] = b1[i - 1] - '0', s[i] = s[i - 1] + a[i];
bool flag = true; int k = 0;
for (int i = n; i >= 1; --i) {
if (k % 2 == 1) {
a[i] ^= 1;
}
if (a[i] == b[i]) continue ;
if (s[i] != i - s[i]) { flag = false; break ; }
++k;
s[i - 1] = i - 1 - s[i - 1];
}
puts(flag == true ? "YES" : "NO");
}
return 0;
}

CF1504B Flip the Bits 题解
https://sobaliuziao.github.io/2021/04/04/post/b341b0a5.html
作者
Egg_laying_master
发布于
2021年4月4日
许可协议