Ответ 1
Многие конкурсные вопросы просят вас вычислить очень большое и очень большое число (например, количество перестановок последовательности из 150 элементов, содержащей некоторое количество дубликатов). Многие языки программирования не поддерживают арифметику произвольной точности, поэтому в интересах справедливости для этих конкурсов целесообразно не запрашивать точное значение. Таким образом, задача заключается в следующем: как может сайт конкурса узнать, когда у вас есть правильный ответ, если вы не можете его точно вычислить?
Одним из изначальных апелляционных вариантов было бы просто попросить ответ по модулю некоторой большой мощности двух (скажем, 2 32 или 2 64), чтобы участники, работающие на языках например C или С++, можно просто использовать uint32_t
или uint64_t
для выполнения всех вычислений, позволяя переполнениям происходить нормально, а затем отправлять результаты. Однако это не особенно желательно. Предположим, например, что вопрос следующий:
Вычислить 10 000!
Это число ошеломляюще огромно и слишком велико, чтобы вписаться в 32-битное или 64-разрядное целое без знака. Однако, если вы просто хотите получить ответ по модулю 2 32 или 2 64 вы можете просто использовать эту программу:
#include <stdio.h>
int main() {
puts("0");
}
Причиной этого является то, что 10 000! является продуктом не менее 5000 четных чисел, поэтому один из его факторов составляет 2 5000. Поэтому, если вы просто хотите получить ответ по модулю 2 32 или 2 64 вам фактически не нужно его вычислять. Вы можете просто сказать, что результат 0 mod 2 32 или 2 64.
Проблема заключается в том, что работающий модуль 2 32 или 2 64 является проблематичным, если полученный ответ чисто делится на любое из этих чисел. Однако, если мы будем работать по модулю большого простого числа, то этот трюк не сработает. Например, число 7 897 987 является простым. Если вы попытаетесь вычислить 10 000! mod 7,897,987, то вы не можете просто сказать "ответ 0", потому что ни один из чисел не умножился в 10 000! являются делителями 7 897 987. Вам действительно нужно сделать какую-то работу, чтобы выяснить, что это число по модулю этого большого числа. В более общем плане, работая по модулю большого прайма, обычно требуется, чтобы вы вычисляли фактический ответ по модулю этого большого числа, а не использовали теоретико-числовые трюки, чтобы полностью пропустить всю работу.
Так зачем работать по модулю 1,000,000,007? Это число является простым (поэтому полезно использовать его как модуль), и оно меньше 2 31 - 1, максимально возможное значение, которое вы можете поместить в 32-битное целое число. Подписанность здесь хороша, потому что на некоторых языках (например, Java) нет целых типов без знака, а целочисленный тип по умолчанию - это 32-разрядное целое число со знаком. Это означает, что вы можете работать по модулю 1,000,000,007, не рискуя переполнением целых чисел.
Подводя итог:
- Работа с модулем большого количества строк делает его вероятным, что если ваша программа производит правильный вывод, он действительно сделал некоторые вычисления и сделал это правильно.
- Работающий по модулю 1,000,000,007 позволяет большому количеству языков использовать свои встроенные целочисленные типы для хранения и вычисления результата.
Надеюсь, это поможет!