Во-первых, в строке много подстрок, я бы сказал, около n ^ 2/2. Это большое число при n = 1e6. Если ваша функция ha sh представляет собой черный ящик без известных свойств arithmeti c, и ваша строка также не имеет известных дополнительных свойств, вам в основном нужно выполнить O (n ^ 2) вызовов вашей функции ha sh, что займет много времени.
Если ваша функция ha sh имеет интересные арифметические свойства c, например, ha sh (a ^ b) = ha sh (a) + ha sh (b) mod K, возможно, у вас получится немного лучше. С другой стороны, такие свойства, вероятно, ослабят ha sh.
В качестве немедленного улучшения вы можете рассмотреть функцию ha sh, которая работает непосредственно с подстрокой. Это сэкономит вам много вызовов String.sub и связанных с ним consing и G C. (Вероятно, это не очень поможет, поскольку у OCaml действительно хороший G C для кратковременных значений.)