БлогNot. Братские числа и Большой Брат натурального числа

Братские числа и Большой Брат натурального числа

Каждое натуральное число имеет бесконечно много кратных ему чисел, в записи которых используются только цифры 0 и 1. Назовём минимальное кратное, обладающее этим свойством, Большим Братом данного числа, а первый и второй сомножители, произведение которых даёт Большого Брата - братскими числами, например, 2 и 5 - братья, а 10 - их Большой Брат, так как 2 * 5 = 10 и 5 * 2 = 10. Это не означает, что у братьев-близнецов 2 и 5 не может быть других братьев, скажем, пятёрка является и братом числа 2022, а 10110 - его Большой Брат (2022 * 5 = 10110, забавно короткий результат получился для числа грядущего года, в отличие от нынешнего). Числа, запись которых уже состоит только из единиц и нулей, ясное дело, имеют братом единицу и сами себе Большие Братья.

Общая картина Братства - это, думаю, отдельный вопрос, который вполне мог бы стать темой для небольшого исследования (все закономерности легко выводятся из факта десятичности и позиционности нашей системы счисления), мне же эта задача хорошо подошла для примера: хотелось побаловаться с числами __int128, но в Studio для 64-битной архитектуры их нормальной поддержки нет, так что в таких случаях проще использовать Qt с компилятором MinGW для x64, там работает.

Соответственно, консольная программа Qt 5.X, представленная ниже, решает нашу задачу.

//Qt 5.X only!
#include <iostream>
#include <vector>

//Служебные функции для __int128
__int128 imax (__int128 a, __int128 b) {
 return (a) > (b) ? (a) : (b);
}

__int128 ipow (__int128 b, __int128 n) {
 if (n == 0) return 1;
 if (n == 1) return b;
 __int128 res = b;
 while (n > 1) {
  res *= b;
  n--;
 }
 return res;
}

__int128 imod (__int128 m, __int128 n) {
 __int128 result = m % n;
 if (result < 0) result += n;
 return result;
}

bool valid (__int128 n) {
 if (n < 0) return false;
 while (n > 0) {
  int r = n % 10;
  if (r > 1) return false;
  n /= 10;
 }
 return true;
}

std::ostream& operator << (std::ostream& os, __int128 n) {
 char buffer[128];
 int pos = (sizeof(buffer) / sizeof(char)) - 1;
 bool negative = false;
 if (n < 0) {
  negative = true;
  n = -n;
 }
 buffer[pos] = 0;
 while (n > 0) {
  int rem = n % 10;
  buffer[--pos] = rem + '0';
  n /= 10;
 }
 if (negative) {
  buffer[--pos] = '-';
 }
 return os << &buffer[pos];
}

//Основной метод
__int128 solve (const __int128 n) {
 if (n == 1) return 1;
 std::vector<__int128> V(n * n, 0);
 V[0] = 1;
 V[1] = 1;
 __int128 m, k, r, j;
 m = 0;
 while (true) {
  m++;
  if (V[(m - 1) * n + imod(-ipow(10, m), n)] == 1) break;
  V[m * n + 0] = 1;
  for (k = 1; k < n; k++) {
   V[m * n + k] = imax(V[(m - 1) * n + k],
                       V[(m - 1) * n + imod(k - ipow(10, m), n)]);
  }
 }
 r = ipow(10, m);
 k = imod(-r, n);
 for (j = m - 1; j >= 1; j--) {
  if (V[(j - 1) * n + k] == 0) {
   r = r + ipow(10, j);
   k = imod(k - ipow(10, j), n);
  }
 }
 if (k == 1) r++;
 return r / n;
}

//Запуск основного метода и контроль вывода
void run (__int128 n) {
 __int128 mult = solve(n);
 if (mult > 0) {
  std::cout << n << " * " << mult << " = " << (n * mult) << '\n';
 }
 else {
  std::cout << n << "(no solution)\n";
 }
}

int main() {
 run(2);
 run(5);
 run(999); //87 бит потребуется
 run(1000);
 run(2021);
 run(2022);
 run(10000);
 //run(100000); //не хватит памяти :(
 return 0;
}

Вывод программы:

2 * 5 = 10
5 * 2 = 10
999 * 111222333444555666777889 = 111111111111111111111111111
1000 * 1 = 1000
2021 * 49481 = 100001101
2022 * 5 = 10110
10000 * 1 = 10000

Самого Большого Брата (для значения 999) проверил умножением вот здесь, совпало.

23.12.2021, 06:54 [635 просмотров]


теги: программирование c++ числа qt

К этой статье пока нет комментариев, Ваш будет первым