1450 words
7 minutes
abc431题解(A~F)
A - Robot Balance
签到。
void solve(int cs){ int a, b; cin >> a >> b; cout << max(a - b, 0ll) << endl;}B - Robot Weight
用 map 记一下零件状态,在x上加加减减即可。
void solve(int cs){ int x, n; cin >> x >> n; vector<int> w(n + 5); for (int i = 1; i <= n; i++) { cin >> w[i]; } map<int, int> ok; int q; cin >> q; while (q--) { int id; cin >> id; if (ok[id] == 1) { ok[id] = 0; x -= w[id]; cout << x << endl; } else { ok[id] = 1; x += w[id]; cout << x << endl; } }}C - Robot Factory
每个身子分配一个他能安装的最大的头,把头和身子从大到小排序后双指针扫一下计数即可。
void solve(int cs){ int n, m, k; cin >> n >> m >> k; vector<int> h(n); vector<int> b(m); int ph = 0, pb = 0; for (int i = 0; i < n; i++) { cin >> h[i]; } for (int i = 0; i < m; i++) { cin >> b[i]; } sort(h.begin(), h.end(), cmp); sort(b.begin(), b.end(), cmp); int cnt = 0; while (ph < n && pb < m) { if (h[ph] <= b[pb]) { cnt++; pb++; } ph++; } cout << (cnt >= k ? "Yes" : "No") << endl;}D - Robot Customize
假定一开始所有的零件都装在身体上,得到一个基础快乐值 ,把第 个零件转移到头上相当于我们的基础快乐值加上 ,同时头部重量加 。考虑总重量为 ,那头部的重量不能超过 。
于是我们可以把这道题转换成物品重量为 ,价值为 ,在容量 下求最大价值和的01背包问题,若最后答案为负数说明把零件放在头上没有快乐值贡献,所以需要将答案与 取 后和基础快乐值 相加。
void solve(int cs){ int n; cin >> n; vector<int> w(n), h(n), b(n); int sw = 0, sb = 0; for (int i = 0; i < n; i++) { cin >> w[i] >> h[i] >> b[i]; sw += w[i]; sb += b[i]; } int m = sw / 2; vector<int> dp(m + 1, -inf); dp[0] = 0; for (int i = 0; i < n; i++) { int del = h[i] - b[i]; if (del <= 0) continue; int wt = w[i]; for (int j = m; j >= wt; j--) { dp[j] = max(dp[j], dp[j - wt] + del); } } int ans = 0; for (int i = 0; i <= m; i++) { if (dp[i] > 0) ans = max(ans, dp[i]); } cout << ans + sb << endl;}E - Reflection on Grid
抽象成一个 01BFS 问题,一个状态由 三部分组成, 为当前格子, 为光的入射方向,对于到达的每一个位置,我们枚举是否需要修改,以及修改成那种类型的镜子,如果无需修改,则将光线到达的下一个格子的状态放到队头;如果需要修改,则将光线到达下一个格子的状态放到队尾,跑 BFS 即可。
struct Node { int x, y, f;};
string dir = "ABC";string s[N];vector<int> d[4][N];
int dx[] = {0, 1, 0, -1};int dy[] = {1, 0, -1, 0};
void nxt(int x, int y, int f, char c, int &nx, int &ny, int &nf) { if (c == 'A') nf = f; else if (c == 'B') nf = (5 - f) % 4; else nf = 3 - f; nx = x + dx[nf]; ny = y + dy[nf];}
void solve(int cs) { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> s[i]; s[i] = ' ' + s[i]; } for (int i = 0; i <= n + 1; i++) { for (int k = 0; k <= 3; k++) { d[k][i].assign(m + 2, inf); } } d[0][1][1] = 0; deque<Node> q; q.clear(); q.push_back({1, 1, 0}); int ans = inf; while (q.size()) { auto [x, y, f] = q.front(); q.pop_front(); int nx, ny, nf, dis; for (auto c : dir) { nxt(x, y, f, c, nx, ny, nf); if (s[x][y] == c) dis = d[f][x][y]; else dis = d[f][x][y] + 1; if (nx == n && ny == m + 1 && nf == 0) ans = min(ans, dis); if (nx == 0 || ny == 0 || nx > n || ny > m) continue; if (dis < d[nf][nx][ny]) { d[nf][nx][ny] = dis; if (s[x][y] == c) q.push_front({nx, ny, nf}); else q.push_back({nx, ny, nf}); } } } cout << ans << endl;}F - Almost Sorted 2
先将数组从小到大排序,我们发现任意一个小于 的值不可能出现在 之后,否则从 向下到该值至少会出现一次相邻下降大于 ,因此令 为使 的最小索引,在 的所有值中索引 的元素必须出现在 以前。因此,当我们按升序把这 个元素放到最终序列时, 在这 个元素中的合法插入位置数为 。将对所有 的选择数相乘,就得到把排序后元素视为可区分物件的排列数。
因为原题中相同元素不可区分,所以要进行去重,如果某个值 在原数组中出现了 次,上面的计数把这 个相同值当作 个不同对象来计数(即标号化),导致重复计数 倍。
故最终答案为:
int qpow(int a, int x, int mod) { int res = 1LL; while (x) { if (x % 2) res = res * a % mod; a = a * a % mod; x /= 2; } return res;}
int fac[N], invFac[N];void init() { fac[0] = 1; for (int i = 1; i < N; ++i) { fac[i] = (fac[i - 1] * i) % MOD; } invFac[N - 1] = qpow(fac[N - 1], MOD - 2, MOD); for (int i = N - 2; i >= 0; --i) { invFac[i] = (invFac[i + 1] * (i + 1)) % MOD; }}
void solve(int cs){ init(); int n, d; cin >> n >> d; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); int ans = 1; for (int i = 0; i < n; i++) { int nd = a[i] - d; int pos = lower_bound(a.begin(), a.end(), nd) - a.begin(); int pk = i - pos + 1; if (pk <= 0) { ans = 0; break; } ans = (ans * (pk % MOD)) % MOD; } int id = 0; while (id < n) { int j = id + 1; while (j < n && a[j] == a[id]) { j++; } int cnt = j - id; ans = (ans * invFac[cnt]) % MOD; id = j; } cout << ans % MOD << endl;} abc431题解(A~F)
https://fuwari.vercel.app/posts/abc/abc431/