Новая Школа - онлайн-школа подготовки к ЕГЭ
Задача Задача №3367947
А
Аноним
09 сентября 2025 11:51 · публичный вопрос
А
Аноним

На c++

Ответ нейросети
09 сентября 2025 11:51

Задача понятна: есть n офисов с заданной высотой(a1…an). За один заказ можно увеличить или уменьшить высоту любого офиса на 1 этаж. Всего есть k заказов. Нужно минимизировать разницу между самым высоким и самым низким офисом после выполнения не более k заказов.

Подход (пошагово, понятно для школьников):

  • Сначала отсортируем массив высот. Тогда изначальный минимум будет в начале, максимум — в конце.
  • Будем работать «с краёв»: поднимем минимальные высоты или опустим максимальные, чтобы сузить диапазон.
  • Пусть текущие минимальная высота L и максимальная R. Посчитаем:
    • cntL — сколько офисов на минимальном уровне L (количество элементов равных L в левом краю).
    • cntR — сколько офисов на максимальном уровне R (количество элементов равных R в правом краю).
  • Сравниваем cntL и cntR:
    • Если cntL ≤ cntR, выгоднее поднимать все офисы на уровне L до следующего различия. Следующий уровень — следующая за L высота в массиве. Стоимость такого подъёма: deltaL * cntL, где deltaL — разница между следующей высотой и текущей L.
    • Иначе выгоднее опускать все офисы на уровне R до предыдущего различия. Стоимость: deltaR * cntR, где deltaR — разница между текущей R и предыдущей высотой.
  • Если стоимость полностью помещается в оставшиеся k заказов, обновляем L или R соответственно и повторяем процесс (переходим к следующей группе одинаковых высот).
  • Если же затрат слишком много, используем остаток k: поднимаем L на floor(k / cntL) или опускаем R на floor(k / cntR), и выходим.
  • Итоговая разница: max(0, R - L).

Сложность: сортировка O(n log n) и один проход сдвигающихся границ — O(n). Используются long long для больших чисел.

Пример кода на C++ (совместим с компиляторами с C++17 и выше):

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    long long n, k;
    if (!(cin >> n >> k)) return 0;
    vector<long long> a(n);
    for (long long i = 0; i < n; ++i) cin >> a[i];

    sort(a.begin(), a.end());

    long long i = 0;           // левая граница (индекс текущего минимального блока)
    long long j = n - 1;       // правая граница (индекс текущего максимального блока)
    long long L = a[i], R = a[j];

    while (L < R && k > 0) {
        // посчитаем количество элементов на минимальном уровне L
        long long i2 = i;
        while (i2 <= j && a[i2] == L) ++i2;
        long long cntL = i2 - i; // сколько элементов имеют высоту L

        // посчитаем количество элементов на максимальном уровне R
        long long j2 = j;
        while (j2 >= i && a[j2] == R) --j2;
        long long cntR = j - j2; // сколько элементов имеют высоту R

        if (cntL <= cntR) {
            // поднимаем левый блок до следующего distinto уровня
            if (i2 > j) break; // все элементы уже учтены, выход
            long long nextL = a[i2];
            long long delta = nextL - L;
            long long cost = delta * cntL;
            if (cost <= k) {
                k -= cost;
                i = i2;
                L = nextL;
            } else {
                long long inc = k / cntL;
                L += inc;
                k -= inc * cntL;
                break;
            }
        } else {
            // опускаем правый блок до предыдущего distinto уровня
            if (j2 < i) break; // все элементы уже учтены, выход
            long long prevR = a[j2];
            long long delta = R - prevR;
            long long cost = delta * cntR;
            if (cost <= k) {
                k -= cost;
                j = j2;
                R = prevR;
            } else {
                long long dec = k / cntR;
                R -= dec;
                k -= dec * cntR;
                break;
            }
        }
    }

    long long answer = (R > L) ? (R - L) : 0;
    cout << answer << "\n";

    return 0;
}

Пояснения по коду:

  • Сортировка нужна, чтобы сгруппировать одинаковые высоты в начале и в конце.
  • i и j — индексы границ текущего диапазона. L и R — текущие минимальная и максимальная высоты внутри этого диапазона.
  • В каждом шаге считаются cntL и cntR — сколько офисов имеют минимальную и максимальную высоты на текущем крае.
  • В зависимости от того, какая сторона “массивнее”, выбирается более выгодная цель поднимать/опускать. Если хватает бюджета, переходим к следующей границе; иначе делаем максимально возможное шаговое изменение и выходим.

Примечания и варианты:

  • Если k достаточно большой, можно полностью выровнять все высоты, и разница станет 0.
  • Альтернативный подход: бинарный поиск разности D и проверка минимального количества операций, чтобы привести все высоты в интервал длиной D. Теперь же двигаемся «по краям» и получаем линейную по времени реализацию после сортировки.

Если хочешь, могу привести тесты на нескольких примерах или разобрать конкретный набор данных из твоего примера.