VP Educational Codeforces Round 77 (Rated for Div. 2)
A. Heating
题意:最多选\(n\)个非负整数,使得它们的和为\(m\),花费为每个数的平方之和。求最小花费。
应该让每个数都尽量接近。那么每个数至少为\(\lfloor \frac{m}{n} \rfloor\),有\(m\% n\)个数需要加一。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
i64 t = m / n;
i64 ans = t * t * (n - m % n) + (t + 1) * (t + 1) * (m % n);
std::cout << ans << "\n";
}
B. Obtain Two Zeroes
题意:给你两个数\(a, b\),你每次选择一个\(x\),使得一个减去\(x\),一个减去\(2x\)。求能不能使得它们都变成零。
发现总共减去\(3x\),那么\(a+b\)应该是\(3\)的倍数。同时\(b \leq 2a\)。这样才能在减完。
点击查看代码
void solve() {
int a, b;
std::cin >> a >> b;
if (a > b) {
std::swap(a, b);
}
if ((a + b) % 3 == 0 && 2 * a >= b) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
C. Infinite Fence
题意:一个数轴,给\(r\)的倍数染红色,\(b\)的倍数染蓝书,\(r, b\)公倍数随便染。然后把染色的点拿出来排成一列。能不能使得没有一个连续长度大于等于\(k\)的相同颜色段。
设\(r < b\)。
那么\([kb + 1, (k + 1)b - 1]\)之间最多放\(\lfloor \frac{(k+1)b - kb - 2)}{r} \rfloor\)个红色点。但直接判断是错的,因为想要放满需要满足从\(kb + 2\)开始放,如何判断呢,其实就是\(rx + by = 1\)。显然需要\(r, b\)互质才能满足,那么就把\(r, b\)除以最大公约数就行。
点击查看代码
void solve() {
i64 r, b, k;
std::cin >> r >> b >> k;
if (r > b) {
std::swap(r, b);
}
i64 d = std::gcd(r, b);
r /= d, b /= d;
if ((b - 2) / r + 1 < k) {
std::cout << "OBEY\n";
} else {
std::cout << "REBEL\n";
}
}
D. A Game with Traps
题意:\(m\)个队员,每个有\(a_i\)敏捷。路径长度为\(n\),一开始你在\(0\)点,有\(k\)个陷阱,每个陷阱布置在\([l_i, r_i]\),有\(d_i\)的危险度,如果\(a_i < d_i\),那么这名队员不能进入。你可以走到\(r_i\)摧毁这个陷阱。每次有两种移动选择,你一个人往左或往右一格,或者你和队员在同一个可以带他们一起移动。求在\(t\)时刻内你最多带几个队员到达\(n+1\)。
考虑二分,我们肯定带前\(x\)个\(a_i\)最大的。那么能带队员走就走,不能走取决于\(a_i\)最小的那个,那么我们需要把这些陷阱摧毁,走到\(r_i\)的过程中可能会遇到新的陷阱有更大的\(r_i\),此时应该一鼓作气走完把这些陷阱摧毁,然后回来接队员。
点击查看代码
void solve() {
int m, n, k, t;
std::cin >> m >> n >> k >> t;
std::vector<int> a(m + 1);
for (int i = 1; i <= m; ++ i) {
std::cin >> a[i];
}
a[0] = 1e9;
std::ranges::sort(a, std::greater<>());
std::vector<std::vector<std::pair<int, int>>> R(n + 1);
for (int i = 0; i < k; ++ i) {
int l, r, d;
std::cin >> l >> r >> d;
R[l].emplace_back(r, d);
}
auto check = [&](int x) -> bool {
int sum = 0;
int r = 0, last = 0;
for (int i = 1; i <= n; ++ i) {
for (auto & [j, v] : R[i]) {
if (v > x) {
r = std::max(r, j);
}
}
++ sum;
if (i == r) {
sum += (r - last) * 2;
last = i;
} else if (i > r) {
last = i;
}
}
sum += n + 1 - last;
return sum <= t;
};
int l = 0, r = m;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(a[mid])) {
l = mid;
} else {
r = mid - 1;
}
}
std::cout << l << "\n";
}
E. Tournament
题意:\(n\)个人,\(n\)是\(2\)的幂。两两打比赛,第\(i\)个人能力为\(i\),两个人比赛能力打的人赢。你的朋友也参加了比赛,你想让他成为最后的赢家。你可以花费\(a_i\)贿赂第\(i\)个人,他就会和你朋友比赛时输掉比赛。你可以随意安排每一场谁和谁打。求最少花费多少贿赂。
如果朋友不是第\(n\)个人,那么必须贿赂第\(n\)个人。如果朋友在\([n / 2 + 1, n - 1]\)这一段,模拟发现最后可以只剩下朋友和第\(i\)个人。否则如果朋友在\([n / 4 + 1, n / 2]\),那么还要贿赂一个人。同理对于每个\(2\)的幂的一段,如果朋友还在前面,就需要贿赂一个。应该贿赂最便宜的。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::priority_queue<int, std::vector<int>, std::greater<>> heap;
i64 ans = 0;
auto lowbit = [&](int x) -> int {
return x & -x;
};
for (int i = n - 1; i >= 0; -- i) {
if (a[i] == -1) {
break;
}
heap.push(a[i]);
if (lowbit(i + 1) == i + 1) {
ans += heap.top();
heap.pop();
}
}
std::cout << ans << "\n";
}