Я решаю проблему программирования, где мне нужно напечатать ответ в формате ответа мод 10 ^ 9 + 7, где «ответ» — это фактический ответ на проблему.
Я выяснил алгоритм для решения проблемы, однако предостережение заключается в том, что ответ на проблему всегда имеет формат m * 10 ^ n, где
1 <= м <= 8 и 2 <= n <= 10 ^ 18, то есть в ответе 10 может быть увеличено до степени 10 ^ 18. Конечно, непосредственное вычисление 10 ^ n может переполниться.
Что я должен делать дальше?
10^n mod M
:Что вам нужно Модульное экспонирование. Это может вычислить (a^b)%m
в log_2(b)
(журнал базы 2).
пример
Допустим, вам нужно вычислить 10^9
,
10
, 9
раз.Или используйте подход «разделяй и властвуй».
10^9 = (10^8)*(10^1)
10^8 = (10^4)*(10^4)
: Нужно ли вычислять 10^4
дважды?
10^4 = (10^2)*(10^2)
: Нужно ли вычислять 10^2
дважды?
10^2 = (10^1)*(10^1)
10^1 = (10^1)*(10^0)
10^0
это базовый случай.
Итак, что мы в основном делаем:
power
нечетное число, то мы вычисляем base^(power-1)
и умножить это на base
получить base^power
, [base^power = (base^(power-1)) * base)
]power
четное число, то мы вычисляем base^(power/2)
и умножить его на себя, чтобы получить base^power
, [base^power = (base^(power/2)) * (base^(power/2))
]. Но мы вычисляем base^(power/2)
только однажды.Вычислительная сложность:
Как указано Вот:
Краткий анализ показывает, что такой алгоритм использует
floor(log_2(n))
кварталы и
в большинствеfloor(log_2(n))
умножения. Точнее,
количество умножений на единицу меньше числа присутствующих
в двоичном разложении п.
Таким образом, мы можем сказать, что время выполнения имеет порядок log_2(n)
, (O(log_2(power))
)
Легко заметить, что при вычислении такого большого значения, как 10^(10^18)
, мы обязаны переполнить даже самый большой из примитивных типов (long long int
). И тут входит Модульное Умножение, в соответствии с которым (a * b) % c = ((a % c) * (b % c)) % c
, В качестве примечания вы можете не увидеть это правило в использовании, когда смотрите непосредственно на код, но оно используется, если вы оцениваете рекурсивные вызовы.
Задача решена?
Мы предотвращаем переполнение, вычисляя модуль по ходу. Скажем, если мы получили какое-то значение как 10^9
и нам нужно умножить это на себя. Переполнение? Нет, не в этот раз
ans = ((10^9 % 1000000007) * (10^9 % 1000000007)) % 1000000007
ans = 10^18 % 1000000007
ans = 49
Хотя существует несколько реализаций, вот простая:
const int M = 1e9 + 7;
long long int powxy(long long int x, long long int y) {
if (y == 0) return 1;
if (y%2 == 1) return (x*powxy(x, y-1))%M;
long long int t = powxy(x, y/2);
return (t*t)%M;
}
проверенный Вот.
Других решений пока нет …