Подтвердить что ты не робот

Наименьшее число, имеющее только 0 и 4 в качестве цифр

Учитывая число A, найдите наименьшее число B, такое, что A * B содержит только цифры 4 и 0, а нули должны быть только в конце, т.е. числа, подобные 404, недействительны.

Например:

| A | B   | A*B |
|---|-----|-----|
| 1 | 4   | 4   |
| 2 | 2   | 4   |
| 3 | 148 | 444 |
| 4 | 1   | 4   |
| 5 | 8   | 40  |

Ну, я поставил вопрос таким образом. Ведение очереди целых чисел. Наименьшее возможное число - 4.

Pop the number (i.e. the front element of the queue) and push the numbers that can be derived from this popped number. 
That is , when we pop 4, we push (4*10) = 40 and (4*10 + 4) = 44 with the constraint that the popped number is not divisible by 10. If it is, push only its next multiple of 10.

Итак, моя очередь будет выглядеть так: 4,40,44,400,440,444,....

По мере того, как я вывожу элементы из очереди, я проверю, делится ли оно заданным номером A. Если да, просто сломайте, и число всплыло, это мой желаемый результат.

Поскольку мой номер может быть действительно большим, я поддерживал очередь pair<string,int>, где строка соответствует number, а int соответствует remainder. Таким образом, остаток следующей стадии может быть легко вычислен.

Пример:

queue : <"4",4> 
Pop , current result is string : "4" and remainder is lets say prev = 4
check if the last digit is 0 or not (for checking if its a multiple of 10 or not)
If not, then append 0 to this string and remainder as (prev*10)%a and push this pair in the queue. Also, append 4 to this string with remainder as : (prev*10 +4)%a and push. If the last digits is 0, append 0(not 4) and corresponding remainder, push this pair in the queue.

Queue: <"40",(prev*10)%a>, <"44", (prev*10 +4)%a> and so on..

Пока пара в передней части очереди не останется 0, мы продолжим делать это.

Хотя это улучшение показалось немного хорошим, но не правильным и не прошло все тестовые примеры. Может кто-то, пожалуйста, рассказать о том, как это нужно решить оптимальным образом. (Диапазон А равен 10 ^ 10).

4b9b3361

Ответ 1

Если я понимаю проблему, решения должны соответствовать выражению regualr 0 | 4 + 0 *

Это манит время, когда я не программирую на C, но следующий код может сделать трюк.

int calc( int n ) {
  int factor5;
  int factor2;
  int j;
  int a;
  int b;
  int i;

  /* trivial case 0 result is 0 */
  if( n==0 ) return 0;

  /* find the number of factors 2 and 5 in n */
  for( a=n, factor5=0; a%5==0; a/=5, factor5++ ); 
  for( a=n, factor2=0; a%2==0; a/=2, factor2++ ); 

  /* result is r=b*a where a=2^(j+2)*5^j */
  j=factor5;
  if( j < factor2-2 ) j=factor2-2; 

  for( a=4,i=0; i<j; i++, a*=10 ); 

  /* generate b in 1, 11, 111, ... until solution found */ 
  for( b=1; (a*b)%n!=0; b=10*b+1 );
  return a*b;
}

он может быть протестирован с помощью:

int main ( void ) {
  int n,r;

  for( n=0; n<10; n++) {
    r=calc(n); printf( "n=%d r=%d\n", n, r );
  }

  return 0;
}

Примечание. Оптимизируйте его. Также замените "int" на "long", "long long" или используйте библиотекарь любых целых чисел.

Тесты:

n=0 r=0
n=1 r=4
n=2 r=4
n=3 r=444
n=4 r=4
n=5 r=40
n=6 r=444
n=7 r=444444
n=8 r=40
n=9 r=444444444

Rationalle:

В дополнение к тривиальному случаю 0 с результатом 0 результат "r" должен соответствовать регулярному выражению "4 + 0 *": четыре с последующими нулями. То есть в нормальной арифметике r = x * 10 ^ j, где x - в 4,44,444,....

Если мы выберем коэффициент 4, то в последовательности 1, 11, 111,... имеем r = x * 4 * 10 ^ j с x. Обратите внимание, что цифры в этой последовательности никогда не имеют коэффициентов 2 и 5 (они не равны даже числам и не заканчиваются на 0 или 5).

В заключение, r = x * 2 ^ (j + 2) * 5 ^ j, с x в 1, 11, 111,... и "j", полученным из факторизации аргумента. На первом этапе программы вычисляется "j", затем вычисляем a = 2 ^ (j + 2) * 5 ^ j и, наконец, генерируем последовательность 1, 11, 111,... и проверяем ее до первого действительного результата.

Ответ 2

Позвоните по 40-значению C, т.е. C = A x B.

Учитывая ограничения, которые я их понимаю, это делает C = AxB из языка 4^n 0^m (не читайте это как 4 к мощности n, он должен означать повторение 4 n раз), поэтому нам нужно только n и m описать C.

Замечания:

  • Поиск наименьшего B эквивалентен поиску наименьшего C, который кратен A.
  • Когда два C -значений имеют различное количество цифр, C с большим числом цифр больше.
  • Если два C -значения имеют равное количество цифр n + m, C с большим числом 4 больше.

Следовательно, мы зацикливаем число цифр в C (начиная с 1 и увеличивая) и на число 4 в C с фиксированным числом цифр, снова начиная с одного 4 и увеличиваться. Это дает нам все возможные числа C в численном порядке.

Как указано и введено в ответ @pasaba por aqui, можно уменьшить пространство поиска, используя тот факт, что A и C могут делиться основными факторами. В этом случае каждый C всегда, по крайней мере, имеет простой коэффициент 2 (2^2 = 4) и, возможно, 5 (2*5 = 10).

Действительно, C = x * 2^(j + 2) * 5^j с x in [1, 11, 111, ...] (т.е. C = x * 4 * 10^j). Наименьший j равен наибольшему числу факторов 2 или 5 в A. Например. если A % 25 == 0, j должно быть 2, если A % 400 == 0, j должно быть 4 и т.д.

См. pasaba por aqui ответ для этого решения.

Версия для грубой силы:

#include <cstdint>
#include <iostream>


int
main(int, char *[])
{
    // use uintmax_t and hope that the number still fits.
    uintmax_t = 13ul; // or whatever

    for (unsigned k = 1u;; ++k) {
        // k is the number of digits
        for (unsigned m = 1u; m <= k; ++m) {
            // m is the number of 4s. 
            // We start at one 4 (zero does not make sense)
            uintmax_t C = 0u;
            // build C, add as many 4s as requested and
            // fill up with zeros
            for (unsigned i = 0; i < k; ++i) {
                if (i < m) {
                    C = C * 10 + 4;
                } else {
                    C = C * 10;
                }
            }
            // check if we have a multiple of A
            if (C % A == 0) {
                std::cout << "C = " << C << std::endl;
                std::cout << "B = " << (C / A) << std::endl;
                return 0;
            }
        }
    }

    return 1;
}

Ответ 3

Здесь я даю эффективный алгоритм, то есть тот, который работает во времени (редактирование: исправление) многочленом в значении А для решения вопроса о числе А. Я также даю доказательство того, что это число N существует для всех чисел А и доказать правильность моего алгоритма - доказательство показывает, что для любого числа A правильный ответ имеет в нем не более A ^ 2 4 (и число нулей не более чем вдвое превышает число цифр A, грубо), (Я не знаю, является ли луч A ^ 2 четверой, но я думаю, что это, вероятно, не слишком далеко). Время работы не будет больше полиномиального размера A или выхода. (Я не совсем это понял.) Увидев другие ответы сейчас, это в основном то же самое, что и pasaba por aqui, но я думаю, что я даю более строгие объяснения, почему это работает. (Хотя мое письмо может быть улучшено, вероятно...)

Терминология: В дальнейшем я скажу, что a number N has the form {STRING} означает, что это десятичное расширение соответствует регулярному выражению {STRING}, хотя это не стандартная терминология терминов.

Задача: Учитывая A, Найдите наименьшее целое число N вида "4 + 0 *" такое, что N mod A = 0

Шаг 1: Рассмотрим 10 mod A и, в частности, последовательность {10 ^ n mod A} для n = 1,2,3,...

Первый очевидный вопрос: что произойдет, если 10 - обратимый mod A, т.е. 10 является взаимно простым для A, а если нет. (Edit: это на самом деле не очевидно, но в 90% этих элементов элементарной теории чисел путь к успеху состоит в том, чтобы сделать некоторый анализ случаев, основанный на первичной факторизации чисел, и думать о том, когда все происходит взаимно, они имеют общие факторы, часто являются хорошим направлением.)

Если 10 не является совпадающим с A, существует несколько возможностей. Один из них состоит в том, что 10 делит A, это глупый случай. Мы можем просто разделить А на 10, найти ответ тогда и умножить его на 10. Если это исключено, то либо 5 делит А, но 2 не делает, либо 2 делит А, а 5 не делает, или А является взаимно простой до 10.

Предположим, что 5 делит A, а 2 - нет. Если N mod A = 0 имеет вид выше, рассмотрим N mod 5 - он равен младшей строке с 5 | 10. Поэтому младший разряд должен быть 0, а не 4, поэтому 10 | N. В этом случае любое целое число вида "4 + 0 *" такое, что N mod A = 0, также имеет N mod 2A = 0. И 10 делит 2A, так что это означает, что мы можем свести к более простой задаче.

Предположим, что 2 делит A, а 5 - нет. Очевидно, что 4 фактически делит любое число формы "4 + 0 *", поэтому для любого нечетного числа A 'наименьшее целое число N, как описано, является тем же самым, считаем ли мы, что A является A', 2A 'или 4A ". Предположим теперь, что 8 делит A. Так как 8 делит любое число формы" 40+", а 8 не делит 4, аналогичным аргументом, как и прежде, следует, что число N должно иметь нуль в качестве нижней цифры, поэтому, если 8 | A, это означает, что если N mod A = 0, то также N mod 5A = 0. Таким образом, мы можем перейти к этому числу, а затем вытащить мощность 10 и свести к более простому вопросу.

Таким образом, мы можем ограничить внимание случаем, когда 10 взаимно прост в A.

Это упрощает, потому что тогда элементарная теория чисел (теорема китайского остатка) говорит нам, что 10 - обратимый mod A, т.е. 10 ^ k = 1 mod A для некоторого достаточно большого k. Это означает также, что мы можем игнорировать возможность нулей в цифрах N - так как если X * 10 ^ y = 0 mod A и 10 - обратимый mod A, мы должны также иметь, что X = 0 mod A, что быть меньшим решением.

Таким образом, как только 10 взаимно прост в A, наименьшее целое число N вида "4 + 0 *" такое, что N mod A = 0 совпадает с наименьшим целым числом вида "4+", для которого N mod A = 0.

(Кроме того, теперь ясно, что всегда существует НЕКОТОРНОЕ целое число N этой формы, которое делится на A. Таким образом, все эти программы действительно заканчиваются и не имеют бесконечного цикла для любого ввода:) Потому что мы можем сделать беспроигрышный анализ. Предположим, что 10 ^ k = 1 mod A. Теперь рассмотрим значение десятичного числа K, составленного из точно k 4, приведенного по модулю A. Если это ноль, то это доказывает, что число существует, и мы закончили. Если это не ноль, то скажем, что это некоторое значение "a" mod A, не равное 0. Мы знаем, что число K * 10 ^ k также равно "a" mod A, потому что 10 ^ k = 1 mod A. А K * 10 ^ k также имеет форму, о которой мы заботимся, и это верно и для K * 10 ^ {ik} для любого i. Таким образом, если взять десятичное число, составленное из точно A * k 4, оно должно быть равно A * a = 0 mod A. Таким образом, мы построили число N искомого вида, которое делится на A.)

Теперь мы можем решить проблему без грубой силы напрямую простым циклом. Мы просто отслеживаем значение "4000000... mod A" и значение "444444.... mod A", где цифры k-цифр длинны, и мы вычисляем эти значения по модулю для k + 1-разрядных чисел, умножая значение первого на значение 10 mod A, уменьшая по модулю A, затем добавляя это также ко второму и уменьшая по модулю A.

Здесь полный код:

#include <cassert>
#include <iostream>

typedef unsigned long long ul;

ul fast_finder(ul A) {
  assert(A);
  ul num_zeros = 0; // remember how many zeros we need to add at the end

  while ((A % 10) == 0) {
    A /= 10;
    ++num_zeros;
  }

  while ((A % 5) == 0) {
    A /= 5;
    ++num_zeros;
  }

  while ((A % 8) == 0) {
    A /= 2;
    ++num_zeros;
  }

  while ((A % 2) == 0) {
    A /= 2;
  }

  ul four_mod_A = 4 % A;
  ul ten_mod_A = 10 % A;

  ul num_fours = 1;
  // in these variable names "k" is the number of fours we are considering
  ul four_times_ten_to_the_k_mod_A = four_mod_A;
  ul sum_of_fours_mod_A = four_mod_A;
  while (sum_of_fours_mod_A) {
    four_times_ten_to_the_k_mod_A *= 10;
    four_times_ten_to_the_k_mod_A %= A;
    sum_of_fours_mod_A += four_times_ten_to_the_k_mod_A;
    sum_of_fours_mod_A %= A;
    ++num_fours;
  }

  // now build an integer representation of the result from num_fours, num_zeros
  ul result = 0;
  while (num_fours) {
    result *= 10;
    result += 4;
    --num_fours;
  }
  while (num_zeros) {
    result *= 10;
    --num_zeros;
  }
  return result;
}

// This is to check the correctness of the fast algorithm, it just the naive algorithm.
ul slow_finder(ul A) {
  assert(A);
  for (ul B = 1;;++B) {
    ul N = B * A;
    bool saw_four = false;
    while (N) {
      ul low = N % 10;
      if (low == 4) {
          saw_four = true;
      } else if (low != 0 || saw_four) { break; }
      N /= 10;
    }
    if (N == 0)
      return A*B;
  }
}

void check(ul x) {
  std::cout << x << ": ";
  ul f = fast_finder(x);
  std::cout << f << std::flush;
  ul s = slow_finder(x);
  if (f != s) {
    std::cout << "failed! ( " << s << " )" << std::endl; return;
  }
  std::cout << '.' << std::endl;
}

int main() {
  check(1);
  check(3);
  check(4);
  check(5);
  check(10);
  check(11);
  check(13);
  check(15);
  check(18);
  check(73);
  check(64);
  check(52);
}