返回顶部

AtCoder Beginner Contest 236 题解

作者:@cherish.
课程学习内容为作者从学校的PPT处摘抄,仅供自己学习参考,若需转载请注明出处:https://www.cnblogs.com/cherish-/p/15843386.html


AtCoder Beginner Contest 236

目前补到F

A - chukodai

题目描述:给你一个字符串s,下标从1开始,再给你两个整数a , b,将字符串中位置a和位置b的字符交换位置并输出交换后的字符串。

思路:根据题意模拟即可

时间复杂度:O(n)

参考代码:

void solve() {
	string s;
	cin >> s;
	int a, b;
	cin >> a >> b;
	swap(s[a - 1], s[b - 1]);
	cout << s << '\n';
}

B - Who is missing?

题目描述:给你4n1张卡片,每张卡片上有一个1n之间的数字,同一数字最多出现4次,有一个数字只出现了三次,请将这个数字找出来。

思路:根据题意模拟即可

时间复杂度:O(n)

参考代码:

void solve() {
	int n;
	cin >> n;
	vector<int>cnt(n + 1, 0);
	int a;
	for (int i = 1; i < 4 * n; ++i) cin >> a, cnt[a]++;
	for (int i = 1; i <= n; ++i) {
		if (cnt[i] == 3) {
			cout << i << '\n';
			return;
		}
	}
	return;
}

C - Route Map

题目描述:给你两个集合S,T,问S的每个元素是否在T中出现过,对于每个元素,若出现过输出Yes,否则输出No

思路:使用setmap等数据结构存储T中的元素,然后遍历S中的元素在使用的数据结构中查找,根据查找结果输出相应的答案即可。

时间复杂度:O(nlogn)

参考代码:

void solve() {
	int n, m;
	cin >> n >> m;
	vector<string>strs(n);
	for (int i = 0; i < n; ++i) cin >> strs[i];
	map<string, bool>mp;
	string s;
	for (int i = 1; i <= m; ++i) {
		cin >> s;
		mp[s] = true;
	}
	for (auto s : strs) {
		if (mp.count(s)) cout << "Yes" << '\n';
		else cout << "No" << '\n';
	}
	return;
}

D - Dance

题目描述:有2n个人,让你将其分成n组,每组中的两个人会有一个匹配值Bi,j其中i , j表示人的编号。问对于所有的分组方案,每一组的匹配值的异或和的最大值是多少。假设每组的匹配值为Ai,即求A1A2...An的最大值。

数据范围:1n8,0Bi,j<230

思路:显然可以爆搜,因为要配对,如果当前已经枚举的人数为偶数,那么任选一个人作为下一组即可,若当前已经分配好的是奇数个,那么就要遍历剩下的人与前一个人组成一队。

时间复杂度:O((2n1)!!)

参考代码:

void solve() {
	int n;
	cin >> n;
	vector<vector<int>>a(2* n + 1, vector<int>(2 * n + 1, 0));
	for (int i = 1; i <= 2 * n - 1; ++i) {
		for (int j = i + 1; j <= 2 * n; ++j) cin >> a[i][j];
	}
	int res = 0, m = n << 1;
	vector<bool>vis(2 * n + 1, false);
	auto dfs = [&](auto dfs, int cur, int cnt, int ans) {
		if (cnt == m) {
			res = max(res, ans);
			return;
		}
		if (cnt % 2 == 0) {
			for (int i = 1; i <= m; ++i) {
				if (vis[i] == true) continue;
				vis[i] = true;
				dfs(dfs, i, cnt + 1, ans);
				vis[i] = false;
				break;
			}
		}
		else {
			for (int i = cur + 1; i <= m; ++i) {
				if (vis[i] == true) continue;
				vis[i] = true;
				int u = cur, v = i;
				dfs(dfs, i, cnt + 1, ans ^ a[u][v]);
				vis[i] = false;
			}
		}
	};
	vis[1] = true;
	dfs(dfs, 1, 1, 0);
	cout << res << '\n';
	return;
}

E - Average and Median

题目描述:给你一个长度为n的序列a,你需要从中选出一些元素组成序列b,选取规则为:1i<n1aiai1至少有一个在序列b中。求序列b的均值的最大值和最大中位数。

数据范围:2n105,1ai109

思路:先考虑这样一个问题,若按照题目的选取规则,求选取的和最大。那么显然可以dp,定义状态fi,gi分别表示不选第i个数和选第i个数字,那么转移方程显然为:

{fi=gi1gi=max(fi1,gi1)+ai

因为只与前一项值有关,所以该递推式可以O(n)时间O(1)空间求解。

回到原问题:我们可以二分平均值的最大值mid,那么将每一项a_i-mid作为c_i,那么原问题就等价于求按照上述选取规则使得b序列的和大于等于0。该过程可以使用上述方法O(n)求解。故求均值的最大值的复杂度为:O(nlog(max1inai))

再来看第二个问题,这是一个比较经典的问题,我们同样可以二分最大中位数mid,然后将序列a数字小于mid的置为-1,将数字大于等于mid的置为1,那么原问题又转化为按照上述规则选取序列a中的元素,使得最大和大于0。该过程使用上述方法同样可以O(n)求解,总复杂度为O(nlogn)

时间复杂度:O(nlogn)

空间复杂度:O(n)

参考代码:

template<class T>
T maximize(vector<T>& nums) {
	T f = 0, g = 0;
	for (auto& num : nums) {
		T u = max(f, g) + num;
		f = g;
		g = u;
	}
	return max(f, g);
}
void solve() {
	int n;
	cin >> n;
	vector<int>nums(n, 0);
	for (auto& num : nums) cin >> num;
	auto average = [&]()->void {
		double lr = 1.0, rs = 1e9 + 5;
		vector<double>b(n);
		while ((rs - lr) / rs > 3e-7) {
			double mid = sqrt(lr * rs);
			for (int i = 0; i < n; ++i) b[i] = nums[i] - mid;
			if (maximize(b) >= 0.0) lr = mid;
			else rs = mid;
		}
		cout << fixed << setprecision(10) << lr << '\n';
		return;
	};
	average();
	auto median = [&]()->void {
		int lr = 1, rs = 1e9 + 5;
		vector<int>b(n);
		while (lr + 1 < rs) {
			int mid = lr + rs >> 1;
			for (int i = 0; i < n; ++i) b[i] = nums[i] >= mid ? 1 : -1;
			if (maximize(b) > 0) lr = mid;
			else rs = mid;
		}
		cout << lr << '\n';
		return;
	};
	median();
	return;
}

F - Spices

题目描述:有2n1个数字1,2,...,2n1,获得一个数字需要花费ci,你的目的是在这些数字中选择一些数字组成集合S,在集合S中选择一些数字进行异或和可以得到12n1之间的所有数字,求最小的花费。

思路:从求集合S的角度来看,是一个比较裸的线性基,学习线性基的相关知识可以参考此处。要使花费最小,可以将数字和花费绑定并按照花费从小到大排序,然后正常求解即可。

时间复杂度:O(2nlog2n)=O(n×2n)

参考代码:

void solve() {
	int n, val;
	cin >> n;
	int m = 1 << n;
	vector<pair<int, int>>a;
	for (int i = 1; i < m; ++i) {
		cin >> val;
		a.push_back({ val , i });
	}
	std::sort(a.begin(), a.end());
	vector<int>p(n + 1, 0);
	long long res = 0;
	for (int i = 1; i <  m; ++i) {
		int tmp = a[i - 1].second;
		for (int j = n; j >= 0; --j) {
			if (((tmp >> j) & 1) == 0) continue;
			if (p[j] == 0) {
				p[j] = tmp;
				res += a[i - 1].first;
				break;
			}
			else tmp ^= p[j];
		}
	}
	cout << res << '\n';
	return;
}
posted @   cherish-lgb  阅读(414)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示