原题链接:
题目3170:蓝桥杯2023年第十四届省赛真题-反异或 01 串
https://www.dotcpp.com/oj/submit_status.php?sid=12146172
完成情况:
解题思路:
解题思路来源于此:
https://blog.dotcpp.com/a/95997
参考代码:
package 蓝桥__真题__专题;
import java.util.Scanner;
import java.util.Vector;
public class _2023试题试题J__反异或01串_02 {
public static void main(String[] args) {
// # 马拉车算法
// # 字符串扩展,每个字母间插入'0',解决奇偶长度回文问题
// s = '0' + '0'.join(list(s)) + '0'
Scanner scanner = new Scanner(System.in);
Vector<Character> s = new Vector<>();
char w;
while (scanner.hasNext()) {
w = scanner.next().charAt(0);
s.add('0');
s.add(w);
}
s.add('0');
int l = 0,r = 0;
int n = s.size();
// # 每个字母的臂长
Vector<Integer> m = new Vector<>(n,0);
// # 初始化,第0个字母臂长肯定是0,即自己
// # m[0] = 0
// '''
// ddabacabac
// l ir
// 2345678
// m[li] = 1
// '''
// 前缀和优化
Vector<Integer> pre = new Vector<>(n+1,0);
if (s.get(0) == '1') {
pre.set(1, 1);
}
int li;
for (int i = 1;i < n;i++) {
if (s.get(i) == '1') {
pre.set(i + 1, pre.get(i) + 1);
}
else {
pre.set(i + 1, pre.get(i));
}
// # 在臂长范围中
if (i < r) {
// # 镜像i位置
li = l - (i - l);
// # 根据回文对称性,获取已知最短臂长
m.set(i, Math.min(r - i, m.get(li)));
}
// # 暴力扩展
while (i+ m.get(i) +1 < n && i- m.get(i) -1 >= 0 && s.get(i + m.get(i) + 1).equals(s.get(i - m.get(i) - 1))) {
m.set(i, 1);
}
// # lr-box更新
if (i + m.get(i) > r) {
l = i;
r = i + m.get(i);
}
}
int res = pre.get(n);
for (int i=0;i<n;i++) {
// # 奇数回文中点不能为 1
if (s.get(i) == '1') {
continue;
}
l = i - m.get(i);
r = i + m.get(i);
// [0,l) + [l,r] / 2 + [r+1,n]
// [l,r] 为回文子字符串,因此 1 个数减半
res = Math.min(res, pre.get(l) + (pre.get(r + 1) - pre.get(l)) / 2 + pre.get(n) - pre.get(r + 1));
}
System.out.println(res);
}
// # 初始化,第0个字母臂长肯定是0,即自己
// # m[0] = 0
}