[补题记录] Educational Codeforces Round 146 (Rated for Div. 2)(A、B、C)

URL:https://codeforces.com/contest/1814

目录

A

Problem/题意

Thought/思路

Code/代码

B

Problem/题意

Thought/思路

Code/代码

C

Problem/题意

Thought/思路

Code/代码


A

Problem/题意

给定 n 和 k,问是否存在 x 和 y,使得 2 * x + k * y = n。

Thought/思路

一开始以为要用扩展欧几里得,然后仔细一想发现,扩欧有解的条件就是 n 是 gcd(a, b) 的倍数,所以直接判断 n 能否整除 gcd(a, b) 即可。

Code/代码

#include "bits/stdc++.h"

#define int long long

signed main() {
	int t; std::cin >> t;
	while (t--) {
		int n, k; std::cin >> n >> k;
		if (n % std::__gcd(2ll, k) == 0) std::cout << "YES" << "\n";
		else std::cout << "NO" <<"\n";
	}
}

B

Problem/题意

一开始你在格子 (0, 0),步长 step = 1。

给出 (a, b),问最少几次操作能从 (0, 0) 到 (a, b)。

操作有:(设现在在格子(x, y))

1.移动到 (x + step, y)

2.移动到 (x, y + step)

3.将步长加一:step = step + 1

Thought/思路

一开始模拟了几个例子,又考虑了一下数据范围,就想到:每次移动都要从当前距离终点的横纵距离中,选一个共同的并且第一个 >= step 的因数来做下一次的步长。

但是WA了。

后来想到,既然最后一定是找到某个步长,使得距离最小,那其实就可以枚举这个步长,维护最小值即可。

Code/代码

#include "bits/stdc++.h"

int solve(int &a, int &b) {
	int ans = 1e9;
	for (int m = 1; m <= (int)1e5; ++ m) {
		ans = std::min(ans, m - 1 + (a + m - 1) / m + (b + m - 1) / m);
	}
	return ans;
}

signed main() {
	int t; std::cin >> t;

	while (t --) {
		int a, b; std::cin >> a >> b;
		std::cout << solve(a, b) << "\n";
	}
}

C

Problem/题意

有 n 种不同颜色的球,同种颜色的球放在一个盒子里面,一共放了 n 个盒子。

给出每种颜色的球,需要查找的次数 cnt[i],并且查找工作由两个 探路者(蒸鸡掰器人) 来做,探路者A查一个盒子需要 s1 秒,探路者B查一个盒子需要 s2 秒。

我们需要设置两个数组,分别由两个探路者在其中查找,问怎么安排这 n 个盒子,使得总查找时间最小。

注意:

找到目标盒子的查找时间,等于“他在数组中的位置 i * 探路者查一个盒子的时间 s”。

Thought/思路

显然要把 cnt 最大的盒子放在数组前面,那么具体放在哪个数组中呢?

假设 s1 = 3,s2 = 1,会有这么一个事实:

一个盒子 x,放在数组B的第三位,和放在数组A的第一位,代价是一样的。

因此,我们可以选择 s 小的数组来放一个盒子,并且要将这个 s += s,意味着在这个数组中的下一位,代价更大了。每次选择代价更小的数组,将盒子放进去即可。

Code/代码

#include "bits/stdc++.h"

struct node {
	int id, cnt;
	bool operator < (const node &t) const {
		return cnt > t.cnt;
	}
};

void solve() {
	int n, s1, s2;
	std::cin >> n >> s1 >> s2;

	std::vector <node> r(n + 1);
	for (int i = 1; i <= n; ++ i) {
		std::cin >> r[i].cnt;
		r[i].id = i;
	}

	std::sort(r.begin() + 1, r.end());

	// for (int i = 1; i <= n; ++ i) std::cout << r[i].cnt << "\n";

	std::vector <int> ans[2];
	int c = s1, d = s2;
	for (int i = 1; i <= n; ++ i) {
		int j = i;
		while (j <= n and c <= d) {
			ans[0].push_back(r[j ++].id);
			c += s1;
		}
		while (j <= n and d <= c) {
			ans[1].push_back(r[j ++].id);
			d += s2;
		}
		i = j - 1;
	}

	int a = ans[0].size(), b = ans[1].size();
	std::cout << a;
	for (int i = 0; i < a; ++ i) {
		std::cout << " " << ans[0][i];
	}
	std::cout << "\n";
	std::cout << b;
	for (int i = 0; i < b; ++ i) {
		std::cout << " " << ans[1][i];
	}
	std::cout << "\n";
}

signed main() {
	int t; std::cin >> t;
	while (t --) {
		solve();	
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值