URL:https://atcoder.jp/contests/abc323
目录
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;
}
}