[补题记录] Atcoder Beginner Contest 323(E、F)

URL:https://atcoder.jp/contests/abc323

目录

E

Problem/题意

Thought/思路

Code/代码

F

Problem/题意

 Thought/思路

Code/代码


E

Problem/题意

有 N 首歌曲,每首歌曲时长为 Ti。每次随机播放一首歌曲,问在 X + 0.5 这一时刻,播放第一首歌的概率是多少。

Thought/思路

如果我们能求出从 X - T[1] + 1 到 X 的每一时刻开始时,恰好播放完上一首歌的概率,那么就可以将这 T[1] 个时刻加起来,再除以 N,就是从 X 开始,播放第一首歌的概率。

因此,dp[i] 表示,第 i 秒开始时,上一首歌结束,下一首歌准备开始播放的概率。

当 i > T[j] 时,就可以把当前第 j 首歌播放的概率累加到 dp[i] 上。

Code/代码

#include "bits/stdc++.h"

#define int long long

const int mod = 998244353;

int n, x, t[10007], dp[10007];

int ksm(int a, int b) {
	int res = 1;
	while (b > 0) {
		if (b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

signed main() {
	std::cin >> n >> x;
	for (int i = 1; i <= n; ++ i) std::cin >> t[i];

	dp[0] = 1;
	for (int i = 1; i <= x; ++ i) {
		int cnt = 0;
		for (int j = 1; j <= n; ++ j) {
			if (i >= t[j]) {
				cnt ++;
				dp[i] = (dp[i] + ksm(n, mod - 2) * dp[i - t[j]] % mod) % mod;
			}
		}
	}

	int s = (x - t[1] + 1 < 0 ? 0 : x - t[1] + 1); // 从 s 开始放
	int ans = 0;
	for (int i = s; i <= x; ++ i) {
		ans = (ans + dp[i]) % mod;
	}
	ans = ans * ksm(n, mod - 2) % mod;

	std::cout << ans;
}

F

Problem/题意

给出三个点的坐标,点 A 表示人、点 B 表示一个箱子、点 C 表示目标点,现在要将箱子推到目标点:

  • 可以将箱子向上、下、左、右推,但人和箱子必须同一朝向且人在箱子之后;
  • 每走一格代价 + 1;
  • 问最小的代价是多少;

 Thought/思路

From:https://zhuanlan.zhihu.com/p/660042738

对于第二句话,我们可以将目标点 C 都换到上半轴,那么 A 只需要移动到 (0, -1)、(-1, 0)、(1, 0) 即可去到推箱子的最佳位置。

详见代码。

Code/代码

#include "bits/stdc++.h"

#define int long long

struct node {
	int x, y;
	node operator - (const node &t) const {
		return node({x - t.x, y - t.y});
	}
}a, b, c;

void reverseAC() {
	c.x = -c.x;
	c.y = -c.y;
	a.x = -a.x;
	a.y = -a.y;
}

signed main() {
	std::cin >> a.x >> a.y;
	std::cin >> b.x >> b.y;
	std::cin >> c.x >> c.y;

	// 以 b 为中心
	a.x -= b.x;
	a.y -= b.y;
	c.x -= b.x;
	c.y -= b.y;
	b.x = b.y = 0;

	int ans = std::abs(c.x) + std::abs(c.y); // 先算 B 到 C 的代价

	if (c.x < 0 and c.y < 0) { // 将 C 偏移到右上方
		reverseAC();
	}
	if (c.x > 0 and c.y > 0) { // A 移动到 -1, 0 或 0, -1
		node p1 = a - node({-1, 0}), p2 = a - node({0, -1});
		// +2 是因为移动箱子时,需要换方向
		ans += std::min(std::abs(p1.x) + std::abs(p1.y), std::abs(p2.x) + std::abs(p2.y)) + 2;
		std::cout << ans;
		return 0;
	}

	if (c.x > 0 and c.y < 0) {
		reverseAC();
	}
	if (c.x < 0 and c.y > 0) {
		node p1 = a - node({1, 0}), p2 = a - node({0, -1});
		ans += std::min(std::abs(p1.x) + std::abs(p1.y), std::abs(p2.x) + std::abs(p2.y)) + 2;
		std::cout << ans;
		return 0;
	}

	if (c.x == 0) { // C 在轴上
		if (c.y < 0) { // 将 C 偏移到正半轴
			reverseAC();
		}
		if (a.x == 0 and a.y > 0) { // A 也在正半轴上,需要绕回负半轴
			ans += 2;
		}
		node p = a - node({0, -1});
		ans += std::abs(p.x) + std::abs(p.y);
		std::cout << ans;
		return 0;
	}
	if (c.y == 0) {
		if (c.x < 0) {
			reverseAC();
		}
		if (a.y == 0 and a.x > 0) {
			ans += 2;
		}
		node p = a - node({-1, 0});
		ans += std::abs(p.x) + std::abs(p.y);
		std::cout << ans;
		return 0;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值