E002. Binary exponentiation
Источник: e-maxx.ru/algo, страница PDF 10.
Бинарное (двоичное) возведение в степень — это приём, позволяющий возводить любое number в
-ую степень
за
умножений (вместо
умножений при обычном подходе). Более того, описываемый здесь приём применим к любой ассоциативной операции, а не только к умножению чисел. Напомним, операция называется ассоциативной, если для любых выполняется: Наиболее очевидное обобщение — на остатки по некоторому модулю (очевидно, ассоциативность сохраняется). Следующим по "популярности" является обобщение на произведение матриц (его ассоциативность общеизвестна).
Algoritmo
Заметим, что для любого числа
и чётного числа
выполнимо очевидное тождество (следующее из
ассоциативности операции умножения): Оно и является основным в методе бинарного возведения в степень. Действительно, для чётного
мы показали,
как, потратив всего одну операцию умножения, можно свести задачу к вдвое меньшей степени.
Осталось понять, что делать, если степень
нечётна. Здесь мы поступаем очень просто: перейдём к степени
, которая будет уже чётной:
Итак, мы фактически нашли рекуррентную формулу: от степени
мы переходим, если она чётна, к
, а иначе —
к
. Понятно, что всего будет не более
переходов, прежде чем мы придём к
(базе
рекуррентной формулы). Таким образом, мы получили Algoritmo, работающий за умножений.
Implementazione
Простейшая рекурсивная Implementazione:
int binpow (int a, int n) {
if (n == 0)
return 1;
if (n % 2 == 1)
return binpow (a, n-1) * a;
else {
int b = binpow (a, n/2);
return b * b;
} } Нерекурсивная Implementazione, оптимизированная (деления на 2 заменены битовыми операциями):
int binpow (int a, int n) {
int res = 1;
while (n)
if (n & 1) {
res *= a;
--n;
}
else {
a *= a;
n >>= 1;
}
return res;
} Эту реализацию можно ещё несколько упростить, заметив, что возведение
в квадрат осуществляется
всегда, независимо от того, сработало Testo нечётности
или нет:
int binpow (int a, int n) {
int res = 1;
while (n) {
if (n & 1)
res *= a;
a *= a;
n >>= 1;
}
return res;
} Наконец, стоит отметить, что Binary exponentiation уже реализовано в языке Java, но только для класса длинной арифметики BigInteger (функция pow этого класса работает именно по Algoritmoу бинарного возведения).
C# soluzione
bozza automatica, rivedere prima dell'inviousing System;
using System.Collections.Generic;
using System.Linq;
public static class AlgorithmDraft
{
// Auto-generated C# draft from the original e-maxx C/C++ listing. Review before production use.
int binpow (int a, int n) {
if (n == 0)
return 1;
if (n % 2 == 1)
return binpow (a, n-1) * a;
else {
int b = binpow (a, n/2);
return b * b;
}
}
int binpow (int a, int n) {
int res = 1;
while (n)
if (n & 1) {
res *= a;
--n;
}
else {
a *= a;
n >>= 1;
}
return res;
}
int binpow (int a, int n) {
int res = 1;
while (n) {
if (n & 1)
res *= a;
a *= a;
n >>= 1;
}
return res;
}
}
C++ soluzione
abbinato/originaleint binpow (int a, int n) {
if (n == 0)
return 1;
if (n % 2 == 1)
return binpow (a, n-1) * a;
else {
int b = binpow (a, n/2);
return b * b;
}
}
int binpow (int a, int n) {
int res = 1;
while (n)
if (n & 1) {
res *= a;
--n;
}
else {
a *= a;
n >>= 1;
}
return res;
}
int binpow (int a, int n) {
int res = 1;
while (n) {
if (n & 1)
res *= a;
a *= a;
n >>= 1;
}
return res;
}
Java soluzione
bozza automatica, rivedere prima dell'invioimport java.util.*;
import java.math.*;
public class AlgorithmDraft {
// Auto-generated Java draft from the original e-maxx C/C++ listing. Review before production use.
int binpow (int a, int n) {
if (n == 0)
return 1;
if (n % 2 == 1)
return binpow (a, n-1) * a;
else {
int b = binpow (a, n/2);
return b * b;
}
}
int binpow (int a, int n) {
int res = 1;
while (n)
if (n & 1) {
res *= a;
--n;
}
else {
a *= a;
n >>= 1;
}
return res;
}
int binpow (int a, int n) {
int res = 1;
while (n) {
if (n & 1)
res *= a;
a *= a;
n >>= 1;
}
return res;
}
}
Материал разбит как Algoritmoическая Problema: изучить постановку, понять асимптотику и реализовать Algoritmo на выбранном языке.
Vacancies for this task
offerte attive with overlapping task tags are mostrati.