反异或01串

题目描述

初始有一个空的 01 串,每步操作可以将 0 或 1 添加在左侧或右侧。也可以对整个串进行反异或操作: 取 s ′ = s ⊕ rev(s),其中 s 是目前的 01 串,⊕ 表示逐位异或,rev(s) 代表将 s 翻转,也就是说取中心位置并交换所有对称的两个位置的字符。例如,rev(0101) = 1010 rev(010) = 010 rev(0011) = 1100。
反异或操作最多使用一次(可以不用,也可以用一次)。
给定一个 01 串 T,问最少需要添加多少个 1 才能从一个空 01 串得到 T。
在本题中 0 可以添加任意个。

输入格式

输入一行包含一个 01 串表示给定的 T 。

输出格式

输出一行包含一个整数,表示需要最少添加多少个 1 。

样例输入

00111011

样例输出

3

别人的c版本:

 1 /* 5003反异或01串 */
 2 // 解题思路:
 3 // S'必定为1个回文串,且当S'的长度为奇数时,最中间的值肯定为0
 4 // 通过S'=S⊕rev(S)可以使得需要1的个数减少1/2
 5 // 根据上述2条性质可以将问题转换为:在S'中找到一个含1最多的回文子串,然后左右扩展1得到S',最终所需1的个数
 6 // 可采用马拉车算法
 7 #include <bits/stdc++.h>
 8 using namespace std;
 9 
10 int manacher5003(string s)
11 {
12     int len = s.size(), maxi = 0, res = 0;
13     int d[len * 2 + 2] = {0};   // 回文串中心半径
14     char t[len * 2 + 2];        // 特殊处理的字符串
15     int pre[len * 2 + 2] = {0}; // 含1前缀和
16     int m = 0;
17     t[++m] = '$';
18     for (int i = 0; i < len; i++)
19         t[++m] = s[i], t[++m] = '$';
20     int mid = 0, right = 0;
21     for (int i = 1; i <= m; i++)
22     {
23         pre[i] = pre[i - 1];
24         if (t[i] == '1')
25             pre[i]++;
26 
27         if (i > right)
28             d[i] = 1;
29         else
30             d[i] = min(d[2 * mid - i], right - i + 1);
31         while (i - d[i] >= 1 && i + d[i] <= m && t[i - d[i]] == t[i + d[i]])
32             d[i]++;
33         if (i + d[i] - 1 > right)
34             mid = i, right = i + d[i] - 1;
35 
36         // if (t[i] != '1' && d[maxi] < d[i])
37         if (t[i] != '1' && pre[i] - pre[i - d[i]] > pre[maxi] - pre[maxi - d[maxi]]) // 用前缀和判断是否是含1最多的回文串
38             maxi = i;                                                                // 记下(中心不为'1'的含'1'最多的回文串的中心下标,例如00100就不行)最大d[i]的下标
39     }
40     // for (int i = 2; i <= m - 1; i++) // 1和m均为'$'
41     // {
42     //     if (i >= maxi && i <= maxi + d[maxi] - 1)
43     //         continue; // 若是最大回文串中的[mid,right]就跳过不计数
44     //     if (t[i] == '1')
45     //         res++;
46     // }
47     // // return *max_element(d, d + m) - 1;
48     // return res;
49     return pre[m] - (pre[maxi] - pre[maxi - d[maxi]]); // 总的含1个数-含1最多的回文串的一半
50 }
51 
52 int main()
53 {
54     cin.tie(0);
55     ios::sync_with_stdio(0);
56     string str;
57     cin >> str;
58     cout << manacher5003(str);
59     return 0;
60 }
61 
62 // 01100101010110
63 // 100001111

自己的java牌代码:

Manacher链接:

posted @ 2024-03-04 14:21  小菜碟子  阅读(143)  评论(0编辑  收藏  举报