Блог пользователя I_love_natalia

Автор I_love_natalia, 13 лет назад, По-русски

Родилась интересная идея в рамках "поделки на коленке", которой спешу поделиться.

Есть много алгоритмов факторизации (например, описанные на e-maxx), но, кажется, что всем им можно понаходить нехорошие контрпримеры в данном диапазоне (по крайней мере, они известные стандартные, и можно ждать подобного, хотя в детали не вдавался - может быть, просветят).

Пусть дано N ≤ 1018. Для начала, проверим маленькие делители до 107 (решето Эратосфена и деления должны уложиться в таком диапазоне). Также проверим, что число не точный квадрат.

Теперь, число либо простое, либо имеет два простых делителя не больше 1011. Попробуем найти функцию Эйлера от числа . Очевидно, что она лежит в диапазоне

Зададимся некоторым a. Предпросчитаем an для n ≤ 107. Если у числа окажется маленький порядок, то просто запомним этот порядок. Иначе с шагом 107 пройдем диапазон значений pq - 1011 - 107 ≤ n ≤ pq - 1 + 107 и обнаружим решения an = 1, в которых одно из n будет являться искомым значением функции . Удостовериться, что данное значение является искомым можно просто решив квадратное уравнение и проверив один из получившихся делителей.

Будем проверять a начиная с двух и так далее. Единственной особенной ситуацией может быть то, что много чисел в начале будут иметь маленький порядок. Будем попутно считать НОК всех получившихся порядков, и, как только этот НОК будет больше 107 проведем процедуру проверки на с шагом НОК.

Не реализовывал, хотя выглядит верным. Discuss.

Upd 1. Сортировать 107 чисел после предпросчета может быть долго. Быть может, надо понизить эту константу до 106 (105 проверок нас вполне устроит). Кроме того, можно использовать тот факт, что делится на 4 и наш шаг делится на 4 и сохранить только 107 / 4 шагов предпросчета.

Upd 2. Итого к реализации: gcd, быстрое возведение в степень, решето Эратосфена, решение квадратного уравнения, точное извлечение корня из числа до 10^18. Не так много и совсем стандартно.

  • Проголосовать: нравится
  • +16
  • Проголосовать: не нравится

13 лет назад, # |
  Проголосовать: нравится +24 Проголосовать: не нравится
Есть вот такой несложный алгоритм http://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
13 лет назад, # |
Rev. 2   Проголосовать: нравится +5 Проголосовать: не нравится

Я всегда проверяю до 10^6, а потом могут остаться максимум 2 простых числа, которые определяю Поллардом-ро. Пока работало.

Кстати, а зачем тут решето Эратосфена? Можно же просто проитерировать все числа от 2 до 10^6 и проверить, делится ли N на них.

  • 13 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    Знаю про ро-эвристику, читал в Кормене, реализовывал. Кажется, на моей реализации были какие-то проблемы иногда, т.е. что можно таки ее заставить работать долго специальными тестами.

    Решето, потому как мне жизненно важен каждый порядок в проверке маленьких простых (мне надо отсечь большое простое).

    У поларда не нравится, в частности, рандомизация.

    Если найдете свою реализацию - дайте пожалуйста, можно погонять.

    • 13 лет назад, # ^ |
        Проголосовать: нравится +1 Проголосовать: не нравится
      Если не нравится рандомизация, то можно найти нерандомизированный алгоритм за . Название не помню, но общий смысл в том, что если n - произведение двух простых, то . Там как-то хитро перебираются претенденты на A, и проверяется что B - квдарат. В сумме получается на отсечение случая когда несколько простых, и  претендентов на А.
      • 13 лет назад, # ^ |
        Rev. 3   Проголосовать: нравится -8 Проголосовать: не нравится

        http://en.wikipedia.org/wiki/Fermat's_factorization_method

        Видимо, речь об этом. Придется писать заодно тест на простоту, ибо

        > If N is prime (so that c = 1), one needs O(N) steps!

        Вообще, это плохой знак. Вполне возможно, что и после теста на простоту если искомые делители различаются раз в 10, будет поломато. Проверю вечером.

        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Нет, он имел ввиду метод Шермана-Лемана (это один человек). Там вся фишка в магическом переборе за кубический корень. Тест на простоту не требуется.
        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Нет, не об этом. Там вроде предполагалось что . И почему-то было постаточно перебирать , . Я мог чуть-чуть нагнать в формулах. Можно проверить что это даст в сумме, заменив суммирование на определенный интеграл.
          • 13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится

            http://ru.wikipedia.org/wiki/Метод_Лемана

            Прочитал. Можно попробовать реализовать, хотя, боюсь, придется неплохо шаманить, в частности, нужна поддержка 128 бит (ручная?) при вычислении корня квадратного из 4*k*n.

            Второй вопрос - получится ли уложить в нормальное время, поскольку придется делать в худшем случае 107 проверок  >64-битного числа на точный квадрат.

            • 13 лет назад, # ^ |
              Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

              Откуда 107. Это где-то 2·105 и даже меньше. При том что это вроде оценка сверху. 

              • 13 лет назад, # ^ |
                Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

                int b1 = sqrt3(n);
                int cnt = 0;
                for (int i=1;i<=b1;i++)
                {
                    int b2 = (int)(pow(double(n), 1.0/6) / 4 / pow (double(i), 1.0/2) + 1);
                   for (int j=0;j<=b2;j++)
                      ++cnt;
                }
                2102446

                Ай! 2*10^6, лишний нолик в выдаче подкрался незаметно. Да, поменьше будет.

        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          Да даже больше могут различаться. Собственно идея в том, что два простых, далёких друг от друга. Уже как-то тестировал, виснит только так.

          пример 999999999809997023 = 56005919 * 17855255617.

  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Вспомнил, что не нравилось в ро-эвристике. Кажется, при неудачном начальном выборе будет зацикливание, и его надо аккуратно ловить.

    Так что хочется Вашу реализацию.

13 лет назад, # |
  Проголосовать: нравится -10 Проголосовать: не нравится
я обычно использую Полларда, Эратосфена и Миллера-Рабина. Приходиться правда всякие вспомогательные алгоритмы писать, типа gcd, бин возведения в степень по модулю, безопасного умножения по модулю. А вообще контрпримеры против этого я даже не представляю как искать, если это вообще возможно. Скорее всего нет (по крайней мере при N < 10^18).
  • 13 лет назад, # ^ |
      Проголосовать: нравится +18 Проголосовать: не нравится

    > я даже не представляю как искать
    > cкорее всего нет

    Домашнее задание. Заставить HashSet<Integer> в Java работать более 2 секунд на сервере Codeforces при последовательном добавлении N = 50000 чисел, не превышающих 10^9