alex0sunny

trash_indicies

Nov 15th, 2021 (edited)
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.80 KB | None | 0 0
  1. # Основная идея решения.
  2. #
  3. # Упорядочить элементы по возрастанию. Посчитать количество пар,
  4. # между которыми разность не больше чем, данная. Если количество
  5. # пар оказалось больше, чем k, то пробуем для меньшей разности,
  6. # если меньше, чем k, то делаем подсчёт для большей разности.
  7. # Используем двоичный поиск при этом.
  8. #
  9. # Подсчёт пар для заданной разности d основан на положении,
  10. # что если разность между крайними числами в промежутке равна d,
  11. # то и все пары в промежутке дают разность не превосходящую d.
  12.  
  13. # Функция выдаёт количество различных пар, которые
  14. # могут дать d элементов.
  15. def count_diffs(d):
  16.     return d / 2 * (d - 1)
  17.  
  18.  
  19. # Функция выдаёт количество различных пар в листе a,
  20. # дающих разности, не превосходящие целевую разность d.
  21. def count_list_diffs(a, d):
  22.     count = l = r = r_prev = 0
  23.     while r < len(a):
  24.         # Находим стартовую (левую) позицию для следующего полуинтервала,
  25.         # включающего пары, с разностью, не превышающей d.
  26.         # В первой итерации внешнего цикла ни одна итерация этого
  27.         # внутреннего цикла выполнена не будет.
  28.         while a[r] - a[l] > d and l < r:
  29.             l += 1
  30.         # Сдвигаем правую границу до тех пор, пока полуинтервал
  31.         # [l; r) не будет включать максимально возможное количество
  32.         # пар, с разностью, не превосходящей d.
  33.         while r < len(a) and a[r] - a[l] <= d:
  34.             r += 1
  35.         # Любая из пар на полуинтервале [l; r) даёт разность,
  36.         # не превосходящую d.
  37.         count += count_diffs(r - l)
  38.         if r_prev - l > 1:
  39.             # Если полуинтервал пересекается с предыдущим, то пары из
  40.             # пересечения-полуинтервала [l; r_prev) учитываются
  41.             # дважды при суммировании количеств. Необходимо вычесть
  42.             # количество, которое даёт пересечение.
  43.             count -= count_diffs(r_prev - l)
  44.         # Сохраняем предыдущее значение r, чтобы потом учесть
  45.         # возможное пересечение полуинтервалов.
  46.         r_prev = r
  47.     return count
  48.  
  49.  
  50. # Найти k-ю по величине разницу между элементами a.
  51. def get_kth(a, k):
  52.     a.sort()
  53.     hi = a[-1]
  54.     lo = 0
  55.     while hi > lo:
  56.         mid = (hi + lo) // 2
  57.         if count_list_diffs(a, mid) < k:
  58.             # Если количество пар для разницы mid меньше k,
  59.             # то целевая разность будет больше mid,
  60.             # следовательно, нижнюю границу lo также
  61.             # можно установить больше mid.
  62.             lo = mid + 1
  63.         else:
  64.             hi = mid
  65.     return lo
  66.  
  67.  
  68. input()
  69. a = [int(x) for x in input().split()]
  70. k = int(input())
  71. print(get_kth(a, k))
  72.  
Add Comment
Please, Sign In to add comment