蓝桥杯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)