分析
发现如果十六进制转二进制时以十进制作为桥,由于十六进制位数很大,转成十进制可能会炸,所以我们可以将十六进制每位分别转成二进制。
接下来考虑 dp
,设状态
[
x
,
0
/
1
,
0
/
1
,
c
]
[x,0/1,0/1,c]
[x,0/1,0/1,c],表示第
x
x
x 位反不反转操作后第
x
x
x 位为
0
/
1
0/1
0/1 且操作次数为
c
c
c,最优化属性为
c
c
c,将状态按非
c
c
c 属性分组,状态转移分类讨论即可,最后答案取
min
(
[
n
,
1
,
0
]
,
[
n
,
0
,
0
]
)
\min([n,1,0],[n,0,0])
min([n,1,0],[n,0,0]) 即可。
代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int kMaxN = 4e6 + 5;
string s, ans;
map<char, string> mp;
int n, f[kMaxN][2][2];
void init() {
mp['0'] = "0000";
mp['1'] = "0001", mp['2'] = "0010", mp['3'] = "0011";
mp['4'] = "0100", mp['5'] = "0101", mp['6'] = "0110";
mp['7'] = "0111", mp['8'] = "1000", mp['9'] = "1001";
mp['A'] = "1010", mp['B'] = "1011", mp['C'] = "1100";
mp['D'] = "1101", mp['E'] = "1110", mp['F'] = "1111";
}
int main() {
cin >> s, init();
for (int i = 0, fl = 0; i < s.size(); i++) {
for (int j = 0; j < 4; j++) {
fl |= (mp[s[i]][j] == '1');
if (fl) {
ans.push_back(mp[s[i]][j]);
}
}
}
n = ans.size(), ans = ' ' + ans;
memset(f, 0x3f, sizeof f);
f[1][0][1] = 0, f[1][1][0] = 1;
for (int i = 2; i <= n; i++) {
if (ans[i] == '0') {
f[i][0][0] = f[i - 1][0][0], f[i][0][1] = f[i - 1][1][0];
f[i][1][0] = f[i - 1][1][1] + 1, f[i][1][1] = f[i - 1][0][1] + 1;
} else {
f[i][0][0] = f[i - 1][1][0], f[i][0][1] = f[i - 1][0][0];
f[i][1][0] = f[i - 1][0][1] + 1, f[i][1][1] = f[i - 1][1][1] + 1;
}
}
int t = min(f[n][1][0], f[n][0][0]);
t <= n ? cout << t : cout << "No";
return 0;
}