B:Reverse Binary Strings | Edu CF Round 97
难度
C
F
∗
1200
CF^*1200
CF∗1200
想了好久,蒙一发结论过了,然后回来证明出来了。
证明怎么这么难
题意
给一个长度为
n
n
n 的
01
01
01 字符串
S
S
S。
字符串的
0
0
0 的数量为
n
2
\frac{n}{2}
2n。
你可以选择
s
s
s 的一个连续子串,然后将其翻转成对应的回文串,例如:
[
0101
11100
‾
]
→
[
0101
00111
‾
]
[0101\underline{11100}]\rightarrow [0101\underline{00111}]
[010111100]→[010100111]
问:求最少的操作次数,使得该串翻转成一个01相间的字符串,比如 [ 0101 ⋯ ] o r [ 1010 ⋯ ] [0101\cdots] or[1010\cdots] [0101⋯]or[1010⋯]
数据范围
2 ≤ n ≤ 1 0 5 2\le n\le 10^5 2≤n≤105
结论
首先将字符串
S
S
S 处理一下:
如果奇数位为
1
1
1,则
T
T
T 串这一位为
1
1
1 ,否则为
0
0
0
如果偶数位为
0
0
0,则
T
T
T 串这一位为
1
1
1 ,否则为
0
0
0
a
n
s
=
min
{
T
0
,
T
1
}
\color{red}ans=\min\{T_0,T_1\}
ans=min{T0,T1}
其中
T
0
T_0
T0 表示串
T
T
T 中有多少串连续的0
其中
T
1
T_1
T1 表示串
T
T
T 中有多少串连续的1
e
.
g
.
e.g.
e.g. 串
S
=
[
11101000
]
S=[11101000]
S=[11101000]
则串
T
=
[
10111101
]
T=[10111101]
T=[10111101]
T
0
=
2
,
T
1
=
3
T_0=2,T_1=3
T0=2,T1=3
a
n
s
=
min
{
2
,
3
}
=
2
ans=\min\{2,3\}=2
ans=min{2,3}=2
解释与证明
- 首先字符串 S S S 处理成 T T T 是表示这一位到底有没有放置正确.
- 若最终串为 [ 1010 ⋯ ] [1010\cdots] [1010⋯] ,则串 T T T 该位为 1 1 1 表示放置正确,该位为 0 0 0 表示放置错误。
- 若最终串为 [ 0101 ⋯ ] [0101\cdots] [0101⋯] ,则串 T T T 该位为 1 1 1 表示放置错误,该位为 0 0 0 表示放置正确。
- 【性质1】易得串 T = [ 010 ] T=[010] T=[010] 和串 T = [ 101 ] T=[101] T=[101] 表示的串本质相同,因为0和1的调换无所谓。
- 我们要操作后变成最终串,其本质就是使得串 T T T 变为全 0 0 0 串
- 接下来,我们分析一下选取子串进行翻转操作的实质:
- 【性质2】若选择的是偶数长度的子串,则对于镜像位置的两个位置
i
,
j
i,j
i,j
若 T i ≠ T j T_i \ne T_j Ti=Tj,则翻转后 T i ′ = T i , T j ′ = T j T^\prime_i=T_i,T^\prime_j=T_j Ti′=Ti,Tj′=Tj
若 T i = T j T_i = T_j Ti=Tj,则翻转后 T i ′ = T i ⊕ 1 , T j ′ = T j ⊕ 1 T^\prime_i=T_i\oplus1,T^\prime_j=T_j\oplus1 Ti′=Ti⊕1,Tj′=Tj⊕1 - 【性质3】若选择的是奇数长度的子串,则对于镜像位置的两个位置
i
,
j
i,j
i,j
若 T i = T j T_i = T_j Ti=Tj,则翻转后 T i ′ = T i , T j ′ = T j T^\prime_i=T_i,T^\prime_j=T_j Ti′=Ti,Tj′=Tj
若 T i ≠ T j T_i \ne T_j Ti=Tj,则翻转后 T i ′ = T j , T j ′ = T i T^\prime_i=T_j,T^\prime_j=T_i Ti′=Tj,Tj′=Ti - 【性质4】奇数位置的 1 1 1 只能和偶数位置的 1 1 1 相互抵消成 0 0 0,因为总体减少 1 1 1的操作只有选择偶数长度的子串才能实现,而这种操作抵消的两个 1 1 1 一定是 奇偶不同的。
- 【接下来,我们对于 T 1 T_1 T1使用第二数学归纳法来做。(对 T 0 T_0 T0使用数学归纳法同理)】
- 定义 f ( x ) \color{cyan}f(x) f(x) 表示 T 1 = x T_1=x T1=x 时的最小操作个数为 f ( x ) f(x) f(x)
- 根据结论,即 f ( x ) = x \color{red}f(x)=x f(x)=x,接下来我们来证明一下。
- 易得 f ( 0 ) = 0 \pmb{f(0)=0} f(0)=0f(0)=0f(0)=0
- 首先,对于 T 1 = 1 T = [ 111 ⋯ ] T_1=1\ T=[111\cdots] T1=1 T=[111⋯],答案显然,翻转次数为1即可变为 T = [ 000 ⋯ ] T=[000\cdots] T=[000⋯],即 f ( 1 ) = 1 \pmb{f(1)=1} f(1)=1f(1)=1f(1)=1
- 其次,对于 T 1 = 2 T_1=2 T1=2
-
T
=
[
00
⋯
0
11
⋯
11
⏟
00
⋯
00
⏟
11
⋯
11
⏟
00
⋯
0
x
个
1
z
个
0
y
个
1
]
T=\begin{bmatrix}00\cdots0&\underbrace{11\cdots11}&\underbrace{00\cdots00}&\underbrace{11\cdots11}&00\cdots0\\&x个1&z个0&y个1\end{bmatrix}
T=[00⋯0
11⋯11x个1
00⋯00z个0
11⋯11y个100⋯0]
开头和结尾的 0 0 0 对答案不影响。然后这里的数据 x , y , z ≥ 1 x,y,z\ge1 x,y,z≥1 才符合定义。
然后, 1 1 1表示该位与最终串的奇偶性不符合。
【若 z z z 为偶数】我们可以选择中间的全 0 0 0 子串,根据性质2,则我们把 f ( 2 ) f(2) f(2) 转化成了 一个新的串 f ( 1 ) f(1) f(1),操作次数当然为 f ( 2 ) = f ( 1 ) + 1 = 2 f(2)=f(1)+1=2 f(2)=f(1)+1=2
【若 z z z 为奇数】因为 0 0 0 的总数为 n 2 \frac{n}{2} 2n ,则第一个全 1 1 1 串的最后一位的奇偶性和后面的全 1 1 1 串的第一位的奇偶性相同。这样根据性质4,我们可以得出结论:一定一个全 1 1 1 串为奇数长,另一个全 1 1 1 串为偶数长。再根据性质2,通过一次翻转把偶数长度的全 1 1 1 串翻转为全 0 0 0 串,也变成 f ( 2 ) = f ( 1 ) + 1 = 2 f(2)=f(1)+1=2 f(2)=f(1)+1=2
⋮ \qquad \vdots ⋮ - 对于 f ( n ) f(n) f(n),若两个全 1 1 1 子串中间的全 0 0 0 子串的长度为偶数,通过性质2可以进行翻转一次,变为 f ( n ) = f ( n − 1 ) + 1 \pmb{f(n)=f(n-1)+1} f(n)=f(n−1)+1f(n)=f(n−1)+1f(n)=f(n−1)+1
- 对于 f ( n ) f(n) f(n),若所有全 1 1 1 子串中间的全 0 0 0 子串的长度都为奇数,则通过性质5可以得到至少有一个全 1 1 1 子串长度为偶数,再通过性质2翻转该全 1 1 1 子串,变成 f ( n ) = f ( n − 1 ) + 1 \pmb{f(n)=f(n-1)+1} f(n)=f(n−1)+1f(n)=f(n−1)+1f(n)=f(n−1)+1
- 【性质5】
∀
n
≥
2
\forall n\ge2
∀n≥2 ,讨论
f
(
n
)
f(n)
f(n) ,若所有全
1
1
1 子串中间的全
0
0
0 子串的长度都为奇数,则至少有一个全
1
1
1 子串长度为偶数。
证明:反证法。若全部全 1 1 1 子串的长度都是奇数,则对于第 1 1 1 个全 1 1 1 子串的开头,最后一个全 1 1 1 子串的结尾,和中间 n − 2 n-2 n−2个全 1 1 1 子串的开头和结尾的奇偶性相同,假设都是奇数。
那么,易得最后奇数位置的 1 1 1 的个数一定比偶数位置的 1 1 1 的个数要多 n n n 个。根据性质4,并且题目输入合法,那么一定会有奇数位置的 1 1 1 的个数和偶数位置的 1 1 1 的个数相同。故矛盾。 - Q.E.D
核心代码
时间复杂度 O ( N ) O(N) O(N)
/*
_ __ __ _ _
| | \ \ / / | | (_)
| |__ _ _ \ V /__ _ _ __ | | ___ _
| '_ \| | | | \ // _` | '_ \| | / _ \ |
| |_) | |_| | | | (_| | | | | |___| __/ |
|_.__/ \__, | \_/\__,_|_| |_\_____/\___|_|
__/ |
|___/
*/
const int MAX = 2e5+50;
const ll MOD = 998244353;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-6;
char aa[MAX];
int oa[MAX];
int ob[MAX];
int main()
{
int T;
scanf("%d",&T);
while(T--){
int len;
scanf("%d%s%*c",&len,aa);
for(int i = 0;i < len;++i){
int jo = i%2;
int shu = aa[i] - '0';
if(shu^jo)oa[i] = 1,ob[i] = 0;
else oa[i] = 0,ob[i] = 1;
}
int sa = 0;
int sb = 0;
int t = 0;
while(t < len && oa[t] == 0)t++;
while(t < len){
while(t < len-1 && oa[t] == 1 && oa[t] == oa[t+1])t++;
sa++;
t++;
while(t < len && oa[t] == 0)t++;
}
t = 0;
while(t < len && ob[t] == 0)t++;
while(t < len){
while(t < len-1 && ob[t] == 1 && ob[t] == ob[t+1])t++;
sb++;
t++;
while(t < len && ob[t] == 0)t++;
}
printf("%d\n",min(sa,sb));
}
return 0;
}