Educational Codeforces Round 69 (Rated for Div. 2)
A. DIY Wooden Ladder
题意:\(n\)个数里选\(k + 2\)个数,使得最大的两个数都大于\(k\)。求最大的\(k\)。
显然最从大的数选更优。那么最大两个数就固定了,给\(a\)排序后,答案就是\(\min(a_{n-1} - 1, n - 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::ranges::sort(a);
std::cout << std::min(a[n - 2] - 1, n - 2) << "\n";
}
B. Pillars
题意:\(n\)个柱子开始有第\(a_i\)个盘子在上面。如果一个柱子上只有一个盘中,那么可以移动到两边的柱子,只要满足这个柱子没有盘子或者这个柱子的盘子大于当前盘子。判断能不能都移动到一个柱子上。
如果\(i\)要到\(i + 1\),那么中间不能有小于它们的数。可以用线段树或者ST表维护区间最小值。但思考发现,满足这个条件的序列一定是一个先递增然后递减的序列。判断是不是满足这个条件就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int l = 0, r = n - 1;
while (l + 1 < n && a[l + 1] > a[l]) {
++ l;
}
while (r - 1 >= 0 && a[r - 1] > a[r]) {
-- r;
}
if (l == r) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
C. Array Splitting
题意:一个递增的数组,分成\(k\)段,每段的值为最大值减最小值。要求和最小。
假设\(k\)段是\([a_1, a_{p_1}], [a_{p_1 + 1}, a_{p_2}], ... , [a_{p_k-1 + 1}, a_n]\)。因为数组是排序的,那么只有每段的端点产生贡献,那么就是\(a_n - a_1 + \sum_{i=1}^{k-1} a_{p_1} - a_{p_1 + 1}\)。我们希望后一项最小,那么可以把所有\(a_i - a_{i+1}\)排序,取前\(k-1\)个最小的。
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
i64 ans = a[n - 1] - a[0];
std::vector<int> b;
for (int i = 0; i + 1 < n; ++ i) {
b.push_back(a[i] - a[i + 1]);
}
std::ranges::sort(b);
for (int i = 0; i + 1 < k; ++ i) {
ans += b[i];
}
std::cout << ans << "\n";
}
D. Yet Another Subarray Problem
题意:选一个子数组\(a_l, .. a_r\)。代价为\((\sum_{i=l}^{r} a_i) - k\times \lceil \frac{r-l+1}{m} \rceil\)。求最大代价。
固定左端点\(i\),发现右端点\(j\)在\(i\% m = j\% m\)时会多减一个\(k\)。同时用前缀和使得\(\sum_{i=l}^{r} a_i = sum_r - sum_{l-1}\)。那么把元素分成\(m\)组,然后一个一个数加入,那么因为子数组是连续的,那么所有\(m\)组都要加上它,同时和它取模\(m\)相同的组要多减一个\(k\),做一个类似最大子段和的东西就行。
点击查看代码
void solve() {
i64 n, m, k;
std::cin >> n >> m >> k;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
const i64 inf = 1e18;
std::vector<i64> sum(m, -inf);
i64 ans = 0;
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
sum[j] += a[i];
}
sum[i % m] = std::max(sum[i % m], a[i]) - k;
for (int j = 0; j < m; ++ j) {
ans = std::max(ans, sum[j]);
}
}
std::cout << ans << "\n";
}