ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AtCoder Beginner Contest 246题解

2022-04-08 13:00:20  阅读:236  来源: 互联网

标签:AtCoder int 题解 nx ny 246 ans 键盘 dis


A - Four Points

题目描述:给你一个矩形的三个顶点坐标,问第四个顶点的坐标。

思路:根据题意模拟即可。

时间复杂度:\(O(1)\)

参考代码:

void solve() {
	int x, y, resx = 0, resy = 0;
	for (int i = 1; i <= 3; ++i) {
		cin >> x >> y;
		resx ^= x; resy ^= y;
	}
	cout << resx << " " << resy << '\n';
	return;
}

B - Get Closer

题目描述:告诉你一条经过原点的直线上的一个点,求这条直线上距离原点长度为\(1\)的点的坐标。

思路:基础的计算几何,若\(x = 0\),直接输出0 1,否则先求出斜率\(k\),然后求解:

\[x^2 + (kx)^2 = 1\\ y = kx \]

即可。

时间复杂度:\(O(1)\)

参考代码:

void solve() {
	int x, y;
	cin >> x >> y;
	if (x == 0) cout << "0 1" << '\n';
	else {
		double k = y * 1.0 / x;
		double resx = sqrt(1.0 / (1 + k * k));
		double resy = resx * k;
		cout << setprecision(10) << resx << " " << resy << '\n';
	}
	return;
}

C - Coupon

题目描述:你需要买\(n\)种物品,每种物品的价格为\(a_i\),给你\(k\)张优惠卷,优惠卷可以叠加,问你买这\(n\)种物品的最小花费。

思路:比较明显的贪心,使用优先队列维护一下当前物品价格的最大值即可。

时间复杂度:\(O(nlogn)\)

参考代码:

void solve() {
	int n, k, x;
	priority_queue<int> heap;
	cin >> n >> k >> x;
	for (int i = 1; i <= n; ++i) {
		int val;
		cin >> val;
		heap.push(val);
	}
	while (k != 0 && !heap.empty()) {
		auto price = heap.top();
		heap.pop();
		if (price <= x) --k;
		else {
			int need = price / x;
			if (need <= k) k -= need;
			else need = k, k = 0;
			price -= need * x;
			if (price != 0) heap.push(price);
		}
	}
	long long res = 0;
	while (!heap.empty()) {
		res += heap.top();
		heap.pop();
	}
	cout << res << '\n';
	return;
}

D - 2-variable Function

题目描述:对于方程\(x = a^3 +a^2b +ab^2 + b^3\),给定一个整数\(n\),求大于等于\(n\)的最小正整数\(x\),使得存在非负整数对\((a , b)\),使得上述等式成立。

思路:显然我们可以枚举\(a\),其范围为\(0 \leq a \leq 1e6\),此时\(a\)可以当做常数看待,原等式可以改写成以下不等式:

\[b^3 + ab^2 + a^2b \geq x - a^3 \]

不等式左边是非负的,所以在正整数范围内以\(b\)为参数的函数是单调递增的,所以可以二分去查找一个最小的\(b\)使得该不等式成立。

时间复杂度:\(O(10^6log10^6)\)

参考代码:

void solve() {
	long long x;
	cin >> x;
	long long res = LLONG_MAX;
	for (int i = 0; i <= 1e6; ++i) {
		long long a = i;
		long long y = x - a * a * a;
		int lr = 0, rs = 1e6, ans = 0;
		while (lr <= rs) {
			long long mid = lr + rs >> 1;
			long long cur = mid * mid * mid + a * mid * mid + a * a * mid;
			if (cur >= y) ans = mid, rs = mid - 1;
			else lr = mid + 1;
		}
		long long cur = a * a * a + 1ll * ans * ans * ans + a * a * ans + a * ans * ans;
		res = min(res, cur);
	}
	cout << res << '\n';
	return;
}

E - Bishop 2

题目描述:你初始时在\((sx , sy)\)位置,你需要到\((ex , ey)\)位置,网格上有障碍物,你只能走斜对角线,每次行走,只要没有障碍物,你可以走任意远。问从起点到终点的最小次数。

思路:比较明显的BFS,但因为一步可以走任意远,所以当当前枚举的点的步数大于枚举的下一个点的步数时提前跳出,进行优化。

时间复杂度:\(O(能过)\)

参考代码:

void solve() {
	int n;
	int sx, sy, ex, ey;
	cin >> n >> sx >> sy >> ex >> ey;
	vector<string>strs(n + 1);
	for (int i = 1; i <= n; ++i) {
		cin >> strs[i];
		strs[i] = ' ' + strs[i];
	}
	vector<vector<int>>dis(n + 1, vector<int>(n + 1, 0x3f3f3f3f));
	dis[sx][sy] = 0;
	using PII = pair<int, int>;
	queue<PII> q;
	q.push({ sx , sy });
	while (!q.empty()) {
		auto [x, y] = q.front();
		q.pop();
		int dist = dis[x][y] + 1;
		for (int d = 1; d <= n; ++d) {
			int nx = x - d, ny = y - d;
			if (nx < 1 || ny < 1 || strs[nx][ny] == '#') break;
			if (dis[nx][ny] < dist) break;
			dis[nx][ny] = dist;
			q.push({ nx , ny });
		}
		for (int d = 1; d <= n; ++d) {
			int nx = x + d, ny = y + d;
			if (nx > n || ny > n || strs[nx][ny] == '#') break;
			if (dis[nx][ny] < dist) break;
			dis[nx][ny] = dist;
			q.push({ nx , ny });
		}
		for (int d = 1; d <= n; ++d) {
			int nx = x + d, ny = y - d;
			if (nx > n || ny < 1 || strs[nx][ny] == '#') break;
			if (dis[nx][ny] < dist) break;
			dis[nx][ny] = dist;
			q.push({ nx , ny });
		}
		for (int d = 1; d <= n; ++d) {
			int nx = x - d, ny = y + d;
			if (nx < 1 || ny > n || strs[nx][ny] == '#') break;
			if (dis[nx][ny] < dist) break;
			dis[nx][ny] = dist;
			q.push({ nx , ny });
		}
	}
	if (dis[ex][ey] == 0x3f3f3f3f) dis[ex][ey] = -1;
	cout << dis[ex][ey] << '\n';
	return;
}

F - typewriter

题目描述:给你\(n\)个键盘, 每个键盘可以打印的字符由一个字符串给出,现在打印长度为\(L\)的字符串,每次可以选择一个键盘打印, 问共可以打印出多少不同的字符串。

思路:考虑容斥,以\(n = 3\)为例,最终答案为:只使用第一个键盘 + 只使用第二个键盘 + 只使用第三个键盘 - 使用第一个和第二个键盘 - 使用第一个和第三个键盘 - 使用第二个和第三个键盘 + 使用所有键盘。考虑到\(n\)很小,可以暴力枚举使用的键盘的数量,然后根据使用数量的奇偶来判断是加还是减,每种情况对答案的贡献为使用的键盘的字符集的交集的模的\(L\)次幂,即假设使用的\(k\)个键盘都含有的字符的种数为\(m\),则对答案的贡献是\(m^L\)。

时间复杂度:\(O(2^n logL)\)

参考代码:

const int mod = 998244353;

void solve() {
	int n, L;
	cin >> n >> L;
	vector<int>typewriter;
	string s;
	for (int i = 0; i < n; ++i) {
		cin >> s;
		int x = 0;
		for (auto&& c : s) x |= (1 << (c - 'a'));
		typewriter.push_back(x);
	}
	auto quickPow = [&](int a, int p)->int {
		int ans = 1;
		while (p) {
			if (p & 1) ans = 1ll * ans * a % mod;
			p >>= 1;
			a = 1ll * a * a % mod;
		}
		return ans;
	};
	auto cal = [](int x)->int {
		int cnt = 0;
		for (int i = 30; i >= 0; --i) cnt += (x >> i) & 1;
		return cnt;
	};
	int res = 0;
	for (int i = 1; i < 1 << n; ++i) {
		int ch = (1 << 26) - 1;
		for (int j = 0; j < n; ++j) {
			if (i & (1 << j)) ch &= typewriter[j];
		}
		int dx = cal(ch), dy = cal(i);
		if (dy & 1) res = (res + quickPow(dx, L)) % mod;
		else res = ((res - quickPow(dx, L)) % mod + mod ) % mod;
	}
	cout << res << '\n';
	return;
}

标签:AtCoder,int,题解,nx,ny,246,ans,键盘,dis
来源: https://www.cnblogs.com/cherish-/p/16116362.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有