【训练题3:字符串+想法(带证明)】B:Reverse Binary Strings | CF 1437

B:Reverse Binary Strings | Edu CF Round 97

难度

C F ∗ 1200 CF^*1200 CF1200
想了好久,蒙一发结论过了,然后回来证明出来了。
证明怎么这么难

题意

给一个长度为 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 2n105

结论

首先将字符串 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=Ti1,Tj=Tj1
  • 【性质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=[000 1111x1 0000z0 1111y1000]
    开头和结尾的 0 0 0 对答案不影响。然后这里的数据 x , y , z ≥ 1 x,y,z\ge1 x,y,z1 才符合定义。
    然后, 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(n1)+1f(n)=f(n1)+1f(n)=f(n1)+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(n1)+1f(n)=f(n1)+1f(n)=f(n1)+1
  • 【性质5】 ∀ n ≥ 2 \forall n\ge2 n2 ,讨论 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 n2个全 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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值