题解: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;
}
posted @ 2025-02-28 22:29  Pdise  阅读(59)  评论(0)    收藏  举报