题解:at_abc391_e Hierarchical Majority Vote

对于一个长度为 3n 的 01 字符串 B=B1B2B3n,定义一种操作获得长度为 3n1 的 01 字符串 C=C1C2C3n1

  • 对于 i=1,2,,3n1,令 CiB3iB3i1B3i2 中出现次数最多的字符。

现给定一个长度为 3N 的 01 字符串 A=A1A2A3N。设 A=A1 是通过 N 次上述操作后得到的长度为 1 的字符串。

请求出最少改变 A 中多少个元素(0110),以改变 A1

1N13


思维好题,把每次操作后的数提取出来,可以得到一个三叉树(注意是从下往上操作的)

我们层层追溯。例如,在上图中,想要根节点改变,我们就要他子节点中为 0 的节点改变其中的一个,要先求出改变三个节点的代价,再对两个 0 节点取 min 即可。

想到可以搜索或 dp,但看到 N​ 的范围,显然直接搜索即可。

我们在搜索的过程本质上是区间操作,考虑搜索参数为区间 [l,r]void dfs(int l, int r)

发现三位数只有 011001111000 这三种可能,当三个节点为 000111 时,我们要操作两次,排序后取 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]); //最小的两个
}

当他们为 001110 时,挑出现次数最多的 01min

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] 之间,容易发现三等分区间分别为:

[l,l+rl+131]   [l+rl+13,l+2×rl+131]   [l+2×rl+13,r]

递归即可:

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 @   lyfandlzf  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示