Будівельна конструкція#10869

Будівельна конструкція (Розбір)

Відсортуємо будівлі за їх висотами так, щоб виконувалася нерівність: h_1 \le h_2 \le ... \le h_n. Якщо декілька будівель мають однакову висоту, упорядкуємо їх додатково за зростанням вартості додавання або видалення цегли.

Розглянемо вартість, необхідну для того, аби привести всі будівлі до висоти h_x~(1 \le x \le n). Вона дорівнює

f(x) = \sum_{i=1}^n |h_i - h_x| \cdot c_i

Функція , яка описує цю вартість, є ввігнутою і має глобальний мінімум, котрий можна знайти за допомогою тернарного пошуку.

Приклад

Розглянемо перший приклад. Відсортуємо будівлі за їх висотами:

Знайдемо значення функції для всіх можливих висот будівель:

Мінімальне значення функції досягається при x = 3; у цьому випадку f(3) = 110.

Реалізація алгоритму

Кожна будівля має висоту і вартість додавання або видалення одного поверху. Інформація про будівлі зберігається в масиві .

#define MAX 100001
struct Building
{
  int h, cost;
};
Building b[MAX];

Функція cmp є компаратором для сортування будівель. Спершу будівлі сортуються за зростанням висоти, а при рівних висотах — за зростанням вартості.

int cmp(Building a, Building b)
{
  if (a.h == b.h)
    return a.cost < b.cost;
  return a.h < b.h;
}

Функція f обчислює вартість, необхідну для того, аби зробити всі будівлі однакової висоти з висотою будівлі номер .

long long f(int x)
{
  long long ret = 0;
  for (int i = 1; i <= n; i++)
    ret += 1LL * abs(b[x].h - b[i].h) * b[i].cost;
  return ret;
}

Функція ternary_search за допомогою тернарного пошуку шукає таке значення x \in [left; right], при якому мінімальна. Спочатку границі діапазону задані як [left; right] = [1; n].

long long ternarySearch(int left, int right)
{
  while (right - left >= 3)
  {
    int a = left + (right - left) / 3;
    int b = left + 2 * (right - left) / 3;
    if (f(a) > f(b))
      left = a;
    else
     right = b;
  }

Різниця між і не перевищує . У цьому випадку мінімальне значення на відрізку [left; right] знаходимо повним перебором.

  long long res = f(left++);
  while (left <= right)
    res = min(res, f(left++));
  return res;
}

Основна частина програми. Читаємо вхідні дані.

scanf("%d", &n);
for (i = 1; i <= n; i++)
  scanf("%d", &b[i].h);
for (i = 1; i <= n; i++)
  scanf("%d", &b[i].cost);

Сортуємо будівлі.

sort(b + 1, b + n + 1, cmp);

Обчислюємо і виводимо відповідь. Будівлі нумеруються від до .

printf("%lld\n", ternarySearch(1, n));