Контест
Мне контест очень понравился, как отличная тренировка решения ботвистых задач. Мне не нравится, когда условие неполно, некорректно, неоднозначно. Здесь же все условия интуитивно понятные (мне) и, вроде, абсолютно корректные.Также, по задачам подготовлены очень хорошие тесты (могу оценивать только то, что дорешал A-C).
Так что, к авторам вообще не может быть претензий, они подготовили оригинальный, качественный сет задач. Лично мне контест очень понравился, хоть и поверг мой рейтинг в пучины отчаяния =).
В каждой комнате все равны перед задачами и взломами, поэтому не вижу проблем с "неравенством" положений, о которых все пишут. Ну сразу же понятно, что в A всякие крайние случаи сыплются, а значит либо аккуратно на бумажке придумываешь решение, либо злостный тест, а лучше и то и другое. А дальше все покажет опыт, как и на других контестах.
Разбор
К сожалению, разбор задачи C мне, наоборот, не понравился. "Точность - это обычный математический объект, и с ним надо уметь строго работать, а не бояться!" (почти точная цитата Андрея Лопатина после лекции 2005 года). Пускай на контесте можно иногда (иногда? никогда!) махнуть рукой, но при разборе такой задачи, по-моему мнению, недопустимо.Я, конечно, совсем не авторитет в этом вопросе, но вот как бы я написал часть про EPS-ны:
1. Есть два принципиальных подхода, считать все точно (т.е. с EPS = 0) или оценивать погрешность своих действий, следя, чтобы она не повлекла за собой WA, а второй, это вычислить EPS, который точно позволит получить ответ с требуемой точностью. Утверждается, что угадывание EPS, это то же самое, что угадывание алгоритма, может повезти, но лучше подумать 10 минут и правильное что-нибудь написать. Кстати в серьезных задачах необходимо сравнивать с разной абсолютной погрешностью.
2. При этом не обязательно в первом случае считать все в целочисленном типе. Пока мантиса не переполнилась (15-16 значащих дес. цифр в double, 20-21 long double) и не совершены операции вносящие погрешность (все кроме + * и / когда делится без остатка) с числами с плавающей точкой можно работать как с целыми. Т.е. сравнивать без всяких EPS.
3. Фраза из разбора: "if (currentTime + addTime > distance / potterSpeed - EPS)" - здесь нельзя убирать EPS, т.к. есть деление! Поставить "маленькое"? как?
Надо вычислить:
Везде в бинпоисках разумно сравнивать времена. Тогда время встречи будет отклоняться от ответа не более, чем на EPS. Отсюда следует, что EPS < 10-6.
Также мы считаем координаты точки с требуемой точностью 10-6, по формуле:
a + dir * dist = a + ((b - a) / |b - a|) * (time * vs).
(Можно оценивать это равенство по всем трем координатам одинаково, они все должны быть вычислены независимо, с одинаковой точностью).
Здесь a и b целые точки из условия, а значит вычислены абсолютно точно.
(b - a) / |b - a| - ошибка будет в последней значащей цифре, не более 2*10-16 (т.к. ответ от [0..1], нормировка вектора - "хорошая" операция: корень ошибется в одном бит. знаке и деление в одном бит. знаке, можно поскладывать относительные погрешности и умножить на 1).
Вообще: нормируйте вектора, вероятности и т.п., это хорошо!
Ошибка time не более EPS, значит, err(time * vs) <= err(time) * 10000 = EPS * 10000.
Отсюда оценка EPS * 10000 <= 10-7 => EPS <= 10-11. (10-7 вместо 10-6, чтобы учесть нормировку).
Значит времена в бин поиске можно сравнивать сточностью 10-11, вещ. типа double хватает.
Как-то так я обычно оцениваю такие штуки. Я неявно пользовался формулами для относительной и абсолютной погрешностей:
abserr(x) = x * relerr(x)
abserr(x + y) = abserr(x - y) = abserr(x)+abserr(y);
relerr(x * y) = relerr(x / y) = relerr(x)+relerr(y);
PS: я был бы рад, если бы кто-нибудь из красных комдивов написал пару страничек в своем блоге, о том, как он считает погрешность на примере нескольких ботвистых задач. Интересует возникающие спец эффекты при сложении и вычитании близких чисел, как изм. точность при исп. стандартных мат. функций и прочее. (Если это случится, пошлите мне ЛС, плз).
PPS: как отметили участники, бин поиск while (r - l) > EPS зависает на хороших тестах, проверено. Стого объянить почему так не берусь (интуитивно: у Вас же всего 16 значащих цифр, а значит рано или поздно, при убывании r - l, будет выполнено m = (l + r) * 0.5 = l).
Надо отсекать по времени или итерациям. Тем более точность вычисления m = (l + r) * 0.5 для некоторого количества итераций, также легко оценивается (чтобы препод по числякам не ругался. Наоборот, там очень любят оценивать этот параметр =) ). После 100 итераций, даже в long double продолжать смысла особого нет.
Здесь сравнение не на равенство, а на больше/меньше... Здесь действительно эпсилону делать нечего. Какая б не была ошибка при делении - мы не знаем в какую она сторону.
Здесь написано:
Если <время Поттера> не больше, чем <время снитча>, то Поттер снитч поймает.
(тут только посылка, правда, заключение опущено)
Причем мы считаем равными времена отстоящие друг от друга менее, чем на EPS.
Поэтому не важно "в какую сторону погрешность" в такой проверке:
greater-or-equal(x, y) <=> x > y - eps;
Если же EPS убрать, то решение может выдать No solution, если не повезет.
Тем не менее - это не важно, критиковалось предложение авторов "поставить EPS сильно меньше, чем...", вместо "правильно оценить погрешность того, что..."
Хотя, возможно, это и имелось ввиду, но оценка - это же основная часть разбора в этой задаче =(
Во-вторых, EPS в проверке на то, выбирать правую или левую границу в том виде, в котором он там, не катит... Это вполне очевидно - он только сдвигает ошибку в одну сторону.
Если уж и лепить куда-то эпсилон тут, так в следующие строчки, где присваивание границ происходит. По типу: rightTime = currentTime + EPS2; else leftTime = currentTime - EPS2; но только EPS2 - это уже другой эпсилон, чтоб поиск сошёлся он должен быть меньше EPS/2 (который в основном цикле), и отражать оценку погрешности вычисления функции (корень которой мы ищем). Тогда алгоритм будет сходится с погрешностью EPS, иначе он сходится с EPS+погрешность вычисления функции. Но только смысла в этом мало, т.к. на практике EPS можно взять сразу меньше требуемой по условию точности вот как раз на максимальную оценку погрешности вычисления функции.
Если Гарри и мяч стартуют из одной точки с одинаковой скоростью, по вашему ответ NO (на концах отрезка ведь знаки одинаковые)? Даже если вы запустите бинарный поиск, то боюсь, без EPS проверка выльется в X > X, с неточно вычисленными X в обеих частях.
Чтоб честно убрать EPS из того условия, нужно ещё проверить не совпадают ли точки старта. В разборе даже намёка на это нет, надеюсь, авторское решение проходит тест с одинаковым стартом.
Читайте внимательнее, речь в том, что вы бинпоиск не запустите на описанном тесте (знак в вершинах ломаной одинаковый, и без разницы проверять с EPS или без), и даже если бинпоиск запустить, то внутренняя проверка даст фейл без EPS.
>и даже если бинпоиск запустить, то внутренняя проверка даст фейл без EPS.
Про проверку на запуск бинпоиска тут речь не шла. Предполагаем, что там всё правильно и мы его запустили. И тогда в случае одинакового старта он сойдётся к этой границе (к старту).
Как внутренняя проверка может дать "фейл без EPS"??? Там выбирается граница (правая/левая) в зависимости от условия больше/меньше, и это всё касательно средины отрезка. No solution уже не получится никак.
Не читали ещё вот этот пост?