и аналогичное сообщение в первом посте я не понял
Идея такая была: например, считаем
. Выпишем все числа:
Понятно, каждому числу из знаменателя можно сопоставить кратное ему из числителя. Пробегаем знаменатель справа налево, сопоставлям. Например, 2-ке сопоставится 92, 3-ке -- 93 или 96, и т.д. Сопоставление находится за одно деление и несколько сложений, да к тому же числитель умещается в кеше, так что получается очень быстро) Сопоставление не взаимнооднозначно (например, там могут быть простые числа), так что некоторым числам числителя будет соответствовать несколько из знаменателя. Так вот, по сопоставленные числа знаменателя можно сократить, получится что-то типа (пишу по памяти, приблизительно):
Т.е. такой наивный алгоритм в данном примере споткнётся на 8 (соответствующая 96 уже участвовала в сокращении). Но и с этим всё просто: если первый раз не удалось найти кратное число (потому что оно уже задействовано в сокращении), то ищем НОД этих двух чисел, сокращаем, переходим к следующему, это тоже делается быстро, где-то за 5-6 шагов. Например, для этого б.к. восьмерка тоже сокращается. И вот, в результате остается только умножение. Причём числа там прорежены и не вызывают быстрого переполнения разрядной сетки, так что на последующем поиске модуля тоже можно сэкономить.
Так вот, такой вот полуторопроходный алгоритм работает исключительно быстро.
(самый худший для него случай) считает где-то за 0.005 секунды. Это очень неплохо для моей задачки!
Но!!! Иногда попадаются несократимые таким образом числа. Их где-то 1/50 от чисел знаменателя. Для них приходится делать дополнительную обработку. И вот возня с ними замедляет алгоритм до 3-5 секунд.
Можно оптимальнее подыскивать парные числа, но мне удалось таким образом раза в два лишь ускорить алгоритм, а этого мало :(