Задача
Натуральное десятичное N - значное число называется числом Армстронга, если сумма его цифр, возведенных в степень N, равна самому числу.
Примеры: 153 = 13 + 53 + 33; 1634 = 14 + 64 + 34 + 44.
Найти все числа Армстронга для 1<=N<=9.
Решение
Конечно, данную задачу можно было решить "в лоб", т.е. сделать простой перебор всех 109 чисел и каждое число проверить. При этом на весьма солидной машине программа могла бы работать достаточно долго. Если бы цель задания заключалась только в нахождении чисел Армстронга, а не в составлении универсальной программы, разработка которой могла бы занимать большое время, то конечно, лучше было бы за 10 минут написать и 3 часа подождать.
Идея уменьшения класса исследуемых чисел заключается в следующем: можно делать перебор не самих чисел, а значений, которые могут получаться в результате степенной суммы (т.е. суммы цифр числа, возведенных в степень числа цифр этого числа). Здесь используется следующее свойство: от перемены цифр местами в числе степенная сумма не меняется. Т.е. например, незачем рассматривать все числа из класса: 135, 153, 315, 351, 531 и 513; достаточно рассмотреть одно из них, например, число 135; вычислить его степенную сумму: (135)ст = 153, а потом лишь убедиться в том что число 153 - это число Армстронга. Этот метод снижает число перебираемых чисел почти в N! раз. Сам же перебор осуществляется довольно просто: рассматриваются все числа, у которых любая цифра не меньше предыдущей и не больше последующей. Например: 12, 1557, 333 и т.д.
Итак, вышеописанный метод снизил число перебираемых чисел с 109 до приблизительно 200000. Но это не все на чем стоит останавливаться. Можно применить еще одну хитрость, которая заключается в следующем: можно значительно ускорить вычисление степенной суммы. Можно заметить, что при вычислениях часто приходится многократно возводить некоторое число в некоторую степень. Чтобы это оптимизировать вводится двухмерный массив, в i-ой строке и j-ом столбце которого находится значение степенной суммы i с основанием j (например, Degree[123,j] = 1j + 2j + 3j). Таким образом, используется значение массива Degree[i,j]. Это существенно ускоряет процесс вычисления, если это сравнивать с некоторым процессом, в котором используется функция Degree(i,j), каждый раз вычисляющая значение ij. Для вычисления выражения 10j аналогично используется массив Degree10. Нужно заметить, что такая операция возведения в степень в программе выполняется более 10000 раз; матрица Degree заполняется в начале программы, где операция возведения i в степень j выполняется около 8000 раз.
В промежутке 1<=N<=9 программа находит следующие 32 числа Армстронга:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 8208, 9474, 54748, 92727, 93084, 548834, 1741725, 4210818, 9800817, 9926315, 24678050, 24678051, 88593477, 146511208, 472335975, 534494836, 912985153.
m-самовлюбленное число - натуральное число, которое равно сумме своих цифр, возведённых в степень m, где m - некоторое натуральное число. Числа Армстронга - частный случай таких чисел.
Число Смита — такое составное число, сумма цифр которого (в данной системе счисления) равняется сумме цифр всех его простых сомножителей. Так, примером числа Смита может служить 202, поскольку 2 + 0 + 2 = 4, и 2 + 1 + 0 + 1 = 4 (202 = 2 * 101). У. Л. МакДэниел доказал, что существует бесконечно много чисел Смита. Насчитывается 29 928 чисел Смита в пределах до 1 000 000. Первые 50 чисел Смита: 4, 22, 27, 58, 85, 94, 121, 166, 202, 265, 274, 319, 346, 355, 378, 382, 391, 438, 454, 483, 517, 526, 535, 562, 576, 588, 627, 634, 636, 645, 648, 654, 663, 666, 690, 706, 728, 729, 762, 778, 825, 852, 861, 895, 913, 915, 922, 958, 985, 1086.
2. Системы счисления
Существует много задач на системы счисления. Для их решения нужно уметь переводить числа между системами счисления. При это генерация определённого числа делается с помощью ДП
| vector<int> toK(int n, int k) { vector<int> rs; while (n >= k) { rs.push_back(n % k); n /= k; } if (n ||!rs.size()) rs.push_back(n); reverse(all(rs)); return rs; } string toKString(int n, int k) { vector<int> t = toK(n, k); reverse(all(t)); string rs = ""; for (auto& i: t) if (i < 10) rs.push_back(i + '0'); else rs.push_back(i - 10 + 'A'); reverse(all(rs)); return rs; } ll numFromKString(string n, int k) { ll rs = 0; ll mult = 1; reverse(all(n)); for (auto& i: n) { if (isdigit(i)) rs += (i - '0') * mult; else rs += (i - 'A' + 10) * mult; mult *= k; } return rs; } ll numFromK(vector<int> n, int k) { ll rs = 0; ll mult = 1; reverse(all(n)); for (auto& i: n) { rs += i * mult; mult *= k; } return rs; } string numbers = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int getIndex(char c) { for (int i = 0; i < 36; ++i) { if (numbers[i] == c) return i; } return -1; } |






