abc 395 题解
ABC
略
D
解题思路
对于操作 2,我们可以将窝对换而企鹅不动。然后就是看实现了
CODE
void solve()
{
int n = 0, q = 0;
std::cin >> n >> q;
// idx 第 i 个位置的窝的编号
// nest 编号为 i 的窝在那个位置
// p 第 i 只企鹅在的位置
std::vector idx(n + 1, 0), nest(n + 1, 0), p(n + 1, 0);
for (int i = 1; i <= n; i++) {
idx[i] = nest[i] = p[i] = i;
}
while (q--) {
int t, a, b;
std::cin >> t;
if (t == 1) {
std::cin >> a >> b;
p[a] = nest[b];
}
else if (t == 2) {
std::cin >> a >> b;
std::swap(idx[nest[a]], idx[nest[b]]);
std::swap(nest[a], nest[b]);
}
else {
std::cin >> a;
std::cout << idx[p[a]] << '\n';
}
}
}
E
解题思路
在正图和矾土两张图里 Dijkstra。具体的,先正图的点 1 入队,常规松弛之后,额外对反图的点 1 进行松弛,即看做正图的点 1 和返图的点 1 之间有一条长度为 \(x\) 的边相连。注意松弛的时候是在正图里松弛还是反图里松弛就好了。
CODE
void solve()
{
int n = 0, m = 0;
i64 x = 0;
std::cin >> n >> m >> x;
for (int i = 0; i < m; i++) {
int u = 0, v = 0;
std::cin >> u >> v;
g1[u].push_back(v);
g2[v].push_back(u);
}
std::priority_queue<std::pair<i64, int>> q;
std::vector dis(2 * n + 1, Inf);
std::vector vis(2 * n + 1, false);
dis[n + 1] = 0;
q.push({ 0, 1 });
auto upd = [&](int cur, i64 d, bool inv) -> void {
for (auto to : (inv ? g2[cur] : g1[cur])) {
if (inv) {
to = -to;
}
if (not vis[n + to] && d + 1 < dis[n + to]) {
dis[n + to] = d + 1;
q.push({ -dis[n + to], to });
}
}
};
while (not q.empty()) {
auto [d, cur] = q.top();
q.pop();
if (vis[n + cur]) {
continue;
}
vis[n + cur] = true;
bool inv = (cur < 0);
upd(std::abs(cur), -d, cur < 0);
if (x - d < dis[n - cur]) {
dis[n - cur] = x - d;
q.push({ d - x, -cur });
}
}
std::cout << std::min(dis[0], dis[n + n]) << '\n';
}
F
解题思路
最主要要观察到这题的二分性质:假设 \(H = h\) 时有一个合法的构造方案,那么对于所有的 \(H \leq h\) 我们都可以找到合法构造方案,即从 \(H = h\) 的构造方案开始,对于每一对 \(U[i]\) 和 \(D[i]\) 优先减 \(U[i]\),这样可以保证相邻两个数的差距只会越来越小。
知道可以二分 \(H\) 后我们就要开始考虑如何 check 了:假设我们已经维护出了 \(U[i - 1]\) 的范围 \([L, R]\),那么对于 \(U[i]\),首先为了满足条件 2,\(U[i]\) 应该在 \([L - x, R + x]\) 中,为了满足条件 1,\(U[i]\) 又应该在 \([max(0, mid - D[i]), min(mid, U[i])]\) 中,于是取两个区间的交集,若为空集则说明该 \(mid\) 不行。对于第 1 个位置,就令区间为 \([0, Inf]\),表示没有条件 2 的影响。
CODE
void solve()
{
int n = 0, x = 0;
std::cin >> n >> x;
std::vector U(n, 0ll), D(n, 0ll);
for (int i = 0; i < n; i++) {
std::cin >> U[i] >> D[i];
}
i64 l = 1, r = Inf;
for (int i = 0; i < n; i++) {
r = std::min(r, U[i] + D[i]);
}
while (l <= r) {
i64 m = l + r >> 1;
i64 L = 0, R = Inf;
for (int i = 0; i < n; i++) {
L = std::max(L - x, std::max(0ll, m - D[i]));
R = std::min(R + x, std::min(m, U[i]));
if (L > R) {
break;
}
}
if (L <= R) {
l = m + 1;
}
else {
r = m - 1;
}
}
i64 ans = 0;
for (int i = 0; i < n; i++) {
ans += U[i] + D[i] - r;
}
std::cout << ans << '\n';
return;
}
浙公网安备 33010602011771号