题解:at_abc391_e Hierarchical Majority Vote
对于一个长度为 \(3^n\) 的 01 字符串 \(B = B_1B_2\dots B_{3^n}\),定义一种操作获得长度为 \(3^{n-1}\) 的 01 字符串 \(C = C_1C_2\dots C_{3^{n-1}}\):
- 对于 \(i = 1,2,\dots,3^{n-1}\),令 \(C_i\) 为 \(B_{3i}\)、\(B_{3i-1}\)、\(B_{3i-2}\) 中出现次数最多的字符。
现给定一个长度为 \(3^N\) 的 01 字符串 \(A = A_1A_2\dots A_{3^N}\)。设 \(A'=A'_1\) 是通过 \(N\) 次上述操作后得到的长度为 \(1\) 的字符串。
请求出最少改变 \(A\) 中多少个元素(\(0\) 变 \(1\),\(1\) 变 \(0\)),以改变 \(A'_1\) 。
\(1 \le N \le 13\)
思维好题,把每次操作后的数提取出来,可以得到一个三叉树(注意是从下往上操作的)
我们层层追溯。例如,在上图中,想要根节点改变,我们就要他子节点中为 \(0\) 的节点改变其中的一个,要先求出改变三个节点的代价,再对两个 \(0\) 节点取 \(\min\) 即可。
想到可以搜索或 dp,但看到 \(N\) 的范围,显然直接搜索即可。
我们在搜索的过程本质上是区间操作,考虑搜索参数为区间 \([l,r]\):void dfs(int l, int r)
发现三位数只有 \(011\),\(001\),\(111\),\(000\) 这三种可能,当三个节点为 \(000\) 或 \(111\) 时,我们要操作两次,排序后取 \(\min\)。
if (cnt[1] == 3) {
int ts[] = {x.cost, y.cost, z.cost}
sort(ts, ts + 3);
return make_pair(0, ts[0] + ts[1]); //最小的两个
}
当他们为 \(001\) 或 \(110\) 时,挑出现次数最多的 \(0\) 或 \(1\) 取 \(\min\)。
if (cnt[1] == 2) {
if (x.val == 1) ans = min(ans, x.cost);
if (y.val == 1) ans = min(ans, y.cost);
if (z.val == 1) ans = min(ans, z.cost);
return make_pair(0, ans);
}
在开始前,需要先求出子节点的最小代价,在 \([l,r]\) 之间,容易发现三等分区间分别为:
\[\left[l,l+\frac{r-l+1}{3}-1\right] \ \ \ \left[l+\frac{r - l + 1}{3},l+2\times \frac{r-l+1}{3}-1\right] \ \ \ \left[l+2\times \frac{r-l+1}{3},r\right]
\]
递归即可:
Node x = dfs(l, l + (r - l + 1) / 3 - 1), y = dfs(l + (r - l + 1) / 3, l + (r - l + 1) / 3 * 2 - 1), z = dfs(l + (r - l + 1) / 3 * 2, r);
完整代码:
// [ABC391E] Hierarchical Majority Vote
// by Pdise
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
#define mkpr make_pair
const int N = 1e5 + 10;
const int INF = 0x7fffffff;
string s;
int n;
PII dfs(int l, int r) {
// cerr << l << " " << r << "\n";
if (l == r) return mkpr(s[l - 1] - '0', 1);
PII x = dfs(l, l + (r - l + 1) / 3 - 1), y = dfs(l + (r - l + 1) / 3, l + (r - l + 1) / 3 * 2 - 1), z = dfs(l + (r - l + 1) / 3 * 2, r);
int cnt[2] = {0, 0};
cnt[x.first] ++, cnt[y.first] ++, cnt[z.first] ++;
// 1 0 0, 1 1 0, 1 1 1, 0 0 0
if (cnt[1] == 3) { // 1 1 1 0
int ts[] = {x.second, y.second, z.second};
sort(ts, ts + 3);
return mkpr(1, ts[0] + ts[1]);
}else if (cnt[0] == 3) { // 0 0 0 1
int ts[] = {x.second, y.second, z.second};
sort(ts, ts + 3);
return mkpr(0, ts[0] + ts[1]);
}else if (cnt[1] == 2) { // 1 1 0 0
int ans = INF - 1;
if (x.first == 1) ans = min(ans, x.second);
if (y.first == 1) ans = min(ans, y.second);
if (z.first == 1) ans = min(ans, z.second);
return mkpr(1, ans);
}else { //0 0 1 1
int ans = INF - 1;
if (x.first == 0) ans = min(ans, x.second);
if (y.first == 0) ans = min(ans, y.second);
if (z.first == 0) ans = min(ans, z.second);
return mkpr(0, ans);
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
cin >> n;
cin >> s;
cout << dfs(1, (int)s.size()).second << "\n";
return 0;
}

浙公网安备 33010602011771号