Солярій для Грибів (Складна)#4361

Солярій для Грибів (Складна) (Розбір)

Розділимо множину точок з цілими координатами на п'ять частин, як показано на рисунку: одна точка знаходиться в центрі, а решта чотири частини симетричні між собою і покривають чотири чверті кола. Якщо кількість точок, що лежать в одній з чвертей, дорівнює , то загальна кількість точок в колі буде 4 \cdot res + 1.

Обчислимо значення . Нехай радіус кола дорівнює . Переберемо значення від до . Тоді на прямій y = k~(0 \le k \le r) усередині кола опиниться \left\lfloor {\sqrt{r^2 - k^2}}\right\rfloor точок з цілими координатами. Загальна кількість таких точок на усіх рівнях і буде значенням :

\sum_{k=0}^r \left\lfloor {\sqrt{r^2 - k^2}}\right\rfloor

Позначимо через загальну кількість цілих точок усередині кола радіуса . Тоді:

f(r) = 4 \cdot \sum_{k=0}^r \left\lfloor {\sqrt{r^2 - k^2}} \right\rfloor + 1

Функція f монотонно зростає. Завдання полягає в тому, щоб знайти мінімальне значення , для якого виконується рівність f(r) = n. Радіус лампи будемо шукати за допомогою бінарного пошуку.

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

Функція count повертає кількість точок з цілими координатами, розташованих усередині кола радіуса .

long long count(long long r)
{
  long long res = 0;
  double r2 = r * r;
  for (long long y = 0; y <= r; y++)
    res += (long long)sqrt(r2 - y*y);
  return 4 * res + 1;
}

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

scanf("%lld",&n);

Радіус кола, який покриває щонайменше точок, шукаємо за допомогою бінарного пошуку. Спочатку припускаємо, що шуканий радіус знаходиться в діапазоні [l; r] = [0; 1000000].

l = 0; r = 1000000;
while (l < r)
{
   m = (l + r ) / 2;

Якщо кількість точок в колі радіуса менша , збільшуємо ліву границю інтервалу до m + 1 — радіуса недостатньо для покриття точок. В іншому випадку зменшуємо праву границю.

   if (count (m) < n) l = m + 1; else r = m;
}

Виводимо відповідь.

printf("%d\n",l);