A. Candy Button
模拟
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, c;
cin >> n >> c;
vector<int> t(n);
rep(i, n) cin >> t[i];
int ans = 0, pre = -c;
rep(i, n) {
if (t[i]-pre < c) continue;
pre = t[i];
ans++;
}
cout << ans << '\n';
return 0;
}
B. Hands on Ring (Easy)
对于左手而言,如果它和目标位置之间有右手存在的话,那只能走另一个方向,否则左手走到目标位置的距离就是二者的差值
右手也是类似
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int f(int n, int s, int t, int x) {
if (s > t) swap(s, t);
if (s < x and x < t) return n-(t-s);
return t-s;
}
int main() {
int n, q;
cin >> n >> q;
int l = 0, r = 1;
int ans = 0;
rep(qi, q) {
char h; int t;
cin >> h >> t;
--t;
if (h == 'L') {
ans += f(n, l, t, r);
l = t;
}
else {
ans += f(n, r, t, l);
r = t;
}
}
cout << ans << '\n';
return 0;
}
C. Prepare Another Box
二分答案
关于判定,先对 \(a\) 做升序排序,然后对将 \(x\) 加入数组 \(b\) 后对 \(b\) 进行排序,\(a_i \to b_i\) 一一对应即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n), b(n-1);
rep(i, n) cin >> a[i];
rep(i, n-1) cin >> b[i];
ranges::sort(a);
const int INF = 1001001001;
int ac = INF, wa = 0;
while (ac-wa > 1) {
int wj = (ac+wa)/2;
auto ok = [&]{
auto nb = b;
nb.push_back(wj);
ranges::sort(nb);
rep(i, n) if (a[i] > nb[i]) return false;
return true;
}();
(ok ? ac : wa) = wj;
}
if (ac == INF) ac = -1;
cout << ac << '\n';
return 0;
}
D. Cycle
先跑一遍BFS求出从点 \(1\) 开始出发到每个点的最短路
对于包含点 \(1\) 的环,一定存在某条有向边指向点 \(1\),假设由点 \(v\) 指向点 \(1\),那么答案就是 \(\min\{\operatorname{dist}[v]+1\}\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> to(n);
rep(i, m) {
int a, b;
cin >> a >> b;
--a; --b;
to[a].push_back(b);
}
const int INF = 1001001001;
vector<int> dist(n, INF);
queue<int> q;
dist[0] = 0; q.push(0);
while (q.size()) {
int v = q.front(); q.pop();
for (int u : to[v]) {
if (dist[u] != INF) continue;
dist[u] = dist[v]+1;
q.push(u);
}
}
int ans = INF;
rep(v, n) {
for (int u : to[v]) {
if (u == 0) {
ans = min(ans, dist[v]+1);
}
}
}
if (ans == INF) ans = -1;
cout << ans << '\n';
return 0;
}
E. Max × Sum
可以先对 \((A_i, B_i)\) 按 \(A_i\) 的大小做升序排序
然后遍历 \(i = k, k+1, \cdots, n\),\(A_i\) 就是当前的最大值,然后从 \(B\) 的前面 \(i-1\) 个数中选出前 \(k-1\) 小的 \(B_j\)
那么现在问题变成了如果找集合里的前 \(k-1\) 小的数的和
考虑实现以下功能的数据结构:
- 添加值
- 删除最大值
可以通过维护大小为 \(k-1\) 的大根堆来实现这两个功能
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
void solve() {
int n, k;
cin >> n >> k;
vector<P> ab(n);
rep(i, n) cin >> ab[i].first;
rep(i, n) cin >> ab[i].second;
ranges::sort(ab);
ll ans = 1e18;
ll sum = 0;
priority_queue<int> q;
for (auto [a, b] : ab) {
sum += b;
if (q.size() >= k-1) {
ans = min(ans, sum*a);
}
q.push(b);
if (q.size() == k) sum -= q.top(), q.pop();
}
cout << ans << '\n';
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}
F. Hands on Ring (Hard)
第一想法是考虑如下dp
记 dp[i][L][R]
表示到第 \(i\) 个操作为止,左手在位置 \(L\) 且右手在位置 \(R\) 处的最小移动代价
可以发现光是状态数就已经爆掉了
注意到,\(H_i\) 对应的手的目标位置已经确定了
记 dp[i][j]
表示到第 \(i\) 个操作为止不是 \(H_i\) 的手的位置为 \(j\) 时的最小移动代价
转移只需考虑“另一只手不动避开”以及“推着另一只手移动”这两种转移方式
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
inline void chmin(int& x, int y) { if (x > y) x = y; }
int main() {
int n, q;
cin >> n >> q;
const int INF = 1001001001;
vector<int> dp(n, INF);
char lh = 'L'; int lt = 0;
dp[1] = 0;
rep(qi, q) {
char h; int t;
cin >> h >> t;
--t;
rotate(dp.begin(), dp.begin()+lt, dp.end());
t = (t-lt+n)%n;
vector<int> old(n, INF);
swap(dp, old);
rep(side, 2) {
rep(i, n) {
if (h == lh) {
if (i <= t) {
chmin(dp[(t+1)%n], old[i] + (t + (t+1)-i));
}
else {
chmin(dp[i], old[i] + t);
}
}
else {
if (i <= t) {
chmin(dp[0], old[i] + (t-i));
}
else {
chmin(dp[(t+1)%n], old[i] + (n-i+t) + (t+1));
}
}
}
reverse(dp.begin()+1, dp.end());
reverse(old.begin()+1, old.end());
t = (n-t)%n;
}
rotate(dp.begin(), dp.begin()+(n-lt), dp.end());
lh = h; lt = (lt+t)%n;
}
int ans = INF;
rep(i, n) chmin(ans, dp[i]);
cout << ans << '\n';
return 0;
}