Ответ 1
Верхнее решение на самом деле O(D*B)
(с использованием проблемной терминологии), но автор заметил, что для большинства ответов D
и B
будет больше, чем 2^32
, и, таким образом, -1
может быть возвращен.
Итак, он вводит maxn
равный 1100 - максимальный D
и F
, для которого имеет смысл подсчитать.
Для D, B = 10000
он сразу возвращает -1. Для D, B = 100
используется рекурсивная формула ниже. Только для некоторых "угловых значений", таких как D = 10000, B = 2
, используется прямая формула. (см. его комментарии для получения подробной информации о "прямой формуле" )
Для D, B < maxn
автор предоставляет формулу в комментариях: f(d,b) = f(d-1,b)+f(d-1,b-1)+1
. Функция F
здесь возвращает максимальное количество этажей, для которых вы можете определить "точку разрыва", используя не более D
попыток и не более B
яиц.
Сама формула должна быть самоочевидной: независимо от того, на каком этаже мы бросаем первое яйцо, есть два результата. Он может сломаться, затем мы можем проверить до f(d-1, b-1)
этажей ниже. Или он может "выжить", тогда мы можем проверить до f(d-1, b)
этажей выше. С текущим полом это делает его f(d-1,b)+f(d-1,b-1)+1
total.
Теперь он может быть легко закодирован как DP (динамическое программирование). Если вы оставите бесконечность (2^32
), то она станет довольно чистой.
for (int i = 1; i < maxn; ++i) {
for (int j = 1; j < maxn; ++j) {
f[i][j] = f[i - 1][j - 1] + f[i - 1][j] + 1;
}
}
Когда у нас есть массив f[D][B]
, сохраняющий эти результаты, поиск D'
и B'
является двоичным поиском. (так как функция F
монотонно растет как с помощью D
, так и B
)
PS Хотя я и сказал в ответ на проблему "кошек" более быстрое решение, это на самом деле круче, чем я имел в виду:) Спасибо вам и sclo (автор)!
Ответ 2
Сильно отредактирован из-за исправления вопроса
Рассмотрим функцию f (x, y), которая дает количество этажей, которые вы можете проверить, с пределом x бросков и y смертей. Если первый бросок приводит к смерти, у вас есть x-1 броски и y-1 смерти, поэтому вы можете проверить полы f (x-1, y-1). Если первый бросок не приведет к смерти, у вас останутся x-1 броски и y смертей, поэтому вы можете проверить f (x-1, y) этажи выше того, из которого вы бросили. Поэтому мы имеем рекуррент f (x, y) = f (x-1, y-1) + f (x-1, y) + 1. Базовые условия заключаются в том, что f (x, 0) = 0 (поскольку if вы делаете даже один бросок, вы рискуете смертью, поэтому вы не можете делать броски и не можете даже проверить первый этаж), а f (1, x) = 1, где x > 0 (вы должны сделать единственный бросок из первый этаж, потому что, если вы выбросите с более высокого этажа и получите смерть, у вас нет результата).
Теперь рассмотрим функцию g (x, y) = SUM 1 <= r <= y of x C r. (Что биномиальный коэффициент, х выбирает г. Я не думаю, что на этом сайте поддерживается обозначение TeX). Утверждение состоит в том, что f (x, y) = g (x, y). Чтобы проверить базовые случаи, рассмотрим, что g (x, 0) представляет собой сумму по 0 элементам, так что соответствует; и g (1, y), где y > 0 дает 1 C 1= 1. Поэтому остается только проверить, что g удовлетворяет рекуррентности.
g (x-1, y-1) + g (x-1, y) + 1 = SUM 1 <= r <= y-1 x-1 C r + SUM 1 <= r <= y x-1 C r + 1
g (x-1, y-1) + g (x-1, y) + 1 = SUM 2 <= r <= y x-1 C r-1 + SUM 1 <= r <= y x-1 C r + 1
g (x-1, y-1) + g (x-1, y) + 1 = SUM 2 <= r <= y x-1 C r-1 + SUM 1 <= r <= y x-1 C r + x-1 C 0к югу >
g (x-1, y-1) + g (x-1, y) + 1 = SUM 1 <= r <= y x-1 C r-1 + SUM 1 <= r <= y x-1 C r
g (x-1, y-1) + g (x-1, y) + 1 = SUM 1 <= r <= y (x-1 C r- 1 + x-1 C r)
g (x-1, y-1) + g (x-1, y) + 1 = SUM 1 <= r <= y (x C r)
g (x-1, y-1) + g (x-1, y) + 1 = g (x, y)
КЭД
На самом деле это можно получить непосредственно, рассматривая его как комбинаторную задачу. Если мы в полной мере используем каждый бит полученной информации, то каждая возможная последовательность выживания или смерти соответствует разному максимальному этажу. Например. за три броска, одну разрешенную смерть, возможности - смерть; Выживание смерть; выживание выживание смерть; или выживаемость выживания. Тем не менее, мы должны уклоняться от случая, когда нет смерти, потому что в этом случае мы не определили пол. Поэтому, если у нас есть x бросков и y разрешенных смертей, мы можем иметь фактическое число смертей r от 1 до y, и для каждого из них мы имеем x C r последовательности. (Если r = y, то любые "пережитки" после смерти y th фактически "не выбрасываются" ).
jdmetz решение для F состоит из оценки g (D, B). Это невозможно сделать лучше, чем время O (min (D, B)), так как для этой суммы нет замкнутой гипергеометрической формы (этот факт можно доказать с использованием алгоритма Госсера).
Добавление
Фактически все три части исходной задачи могут быть выполнены в линейном времени (при условии, что умножение и арифметика являются операциями с постоянным временем, которые мы имеем до сих пор - не верно, но мы оставим это в стороне). Операция O (n lg n) в решении jdmetz находит наименьшее D такое, что f (D, B) > F.
Если объединить нашу исходную рекуррентность f (D, B) = f (D-1, B-1) + f (D-1, B) + 1 с разностью термов от формы g, f (D, B) = f (D, B-1) + D C B получаем f (D, B) = 2 * f (D-1, B) + 1 - D-1 C B. Затем мы можем использовать a C b= a-1 C b * a/(a - b) to цикл над D из 1.
private static int d_opt(final long f, final int b)
{
int d = 0, dCb = 0;
long f_db = 0;
while (f_db < f)
{
dCb = (d == b) ? 1 : d * dCb / (d-b);
f_db = 2 * f_db + 1 - dCb;
d++;
}
return d;
}