蓝桥杯2023省赛 反异或01串 题解

蓝桥杯2024省赛压轴题

原题链接https://www.acwing.com/problem/content/5397/

思路详解

分析反异或+马拉车算法

假设输入字符串为 S。题目关键点在于 s′ = s ⊕ rev(s) 可以s使得字符串 s进行一次该公式反转,然后再前后拼接 01 ,生成目标字符串 S。

那么该公式反转到底有什么用呢?根据异或定义,两个位不相同返回1,相同返回0,假设 n 为字符串s的长 度。

当 s’[i] = 1 时,s与rev(s)对应的位不相同,即 s[i] != s[n-i-1]

当 s’[i] = 0 时,s与rev(s)对应的位相同,即 s[i] == s[n-i-1]

根据上述情况,可以得到另一个结论 :

当 s[i] != s[n-i-1] 时 s’[i] = 1,s’[n-i-1] = 1

当 s[i] == s[n-i-1] 时 s’[i] = 0,s’[n-i-1] = 0

因此可以发现 s’ 必为一个回文字符串

特殊情况,当 s’ 长度为奇数时,s 长度也为奇数,s 和 rev(s)最中间的值必定相同,所以 s’ 最中间的值肯定为 0

得到 s’ 必为一个回文字符串又有何用呢?举个例子,假如 s’ = 1111:

那么原s可以为 1010 , 0101 , 1100 , 0011, 可以发现无论哪种情况,1的个数都变成了二分之一

因此通过 s′ = s ⊕ rev(s) 公式转换,可以使需要1的个数减少二分之一

题目可以转化为在 S 中找到一个 回文子字符串,且该回文子字符串中含有 1 的个数最多。

可以根据中心扩展方法,枚举S中所有位,以该位为中心,左右扩展得到该位得最长 回文字符串

当然普通得中心扩展方法肯定达不到100%ac,因为时间复杂度为 O(n2),因此需要马拉车算法(Manacher)

时间复杂度 O ( n ) O(n) O(n)
python 代码
import sys
input = lambda: sys.stdin.readline().strip()
s = input()
n = len(s)
m = n * 2 + 1
p = [0 for _ in range(m + 10)]
Len = [0 for _ in range(m + 10)]
pre = [0 for _ in range(m + 10)]
p[0] = '!'
for i in range(1 , m , 2) :
    p[i] = '#'
    p[i + 1] = s[i // 2]
p[m] = '#'
p[m + 1] = '@'
p0 , P = 0 , 0
for i in range(1 , m + 1) :
    pre[i] = pre[i - 1]
    if p[i] == '1' :
        pre[i] += 1
    if P > i :
        Len[i] = min(P - i, Len[p0 * 2 - i])
    else :
        Len[i] = 1
    while p[i + Len[i]] == p[i - Len[i]] :
        Len[i] += 1
    if Len[i] + i > P :
        P , p0 = Len[i] + i , i
res , ans = pre[m], 10 ** 9
pre[m + 1] = pre[m]
for i in range(1 , m + 1) :
    if p[i] == '1' :
        continue
    cnt = pre[i + Len[i]] - pre[i - Len[i] - 1]
    ans = min(ans , res - cnt // 2 )
print(ans)

你可能感兴趣的:(python,蓝桥杯,算法,数据结构)