Regex (ECMAScript), 131 байт
Принаймні -12 байт завдяки Deadcode (у чаті)
(?=((xx+)(?=\2+$)|x+)+)(?=((x*?)(?=\1*$)(?=(\4xx+?)(\5*(?!(xx+)\7+$)\5)?$)(?=((x*)(?=\5\9*$)x)(\8*)$)x*(?=(?=\5$)\1|\5\10)x)+)\10|x
Спробуйте в Інтернеті!
Вихід - це довжина відповідності.
Регекси ECMAScript вкрай важко нічого підрахувати. Будь-яка зворотна зміна, визначена поза циклом, буде постійною під час циклу, будь-яка зворотна заздалегідь визначена всередині циклу буде скинута під час циклу. Таким чином, єдиний спосіб перенести стан через ітерації циклу - це використання поточного положення відповідності. Це єдине ціле число, і воно може лише зменшуватися (ну, положення збільшується, але довжина хвоста зменшується, і саме це ми можемо зробити з математики).
Враховуючи ці обмеження, просто підрахувати число копріметів видається неможливим. Натомість ми використовуємо формулу Ейлера для обчислення суті.
Ось як це виглядає в псевдокоді:
N = input
Z = largest prime factor of N
P = 0
do:
P = smallest number > P that’s a prime factor of N
N = N - (N / P)
while P != Z
return N
Про це є дві сумнівні речі.
По-перше, ми не економимо дані, а лише поточний продукт, тож як ми можемо дійти до основних факторів введення? Хитрість полягає в тому, що у (N - (N / P)) є такі ж прості коефіцієнти> P, як і N. Це може отримати нові прості коефіцієнти <P, але ми все одно їх ігноруємо. Зауважте, що це працює лише тому, що ми повторюємо найважливіші фактори від найменших до найбільших, інакше не вдасться.
По-друге, ми повинні запам'ятати два числа через ітерації циклу (P і N, Z не рахується, оскільки це постійне), і я просто сказав, що це неможливо! На щастя, ми можемо згорнути ці два числа в одному. Зауважимо, що на початку циклу N завжди буде кратним Z, тоді як P завжди буде меншим за Z. Таким чином, ми можемо просто запам'ятати N + P і витягувати P з модулем.
Ось трохи детальніший псевдо-код:
N = input
Z = largest prime factor of N
do:
P = N % Z
N = N - P
P = smallest number > P that’s a prime factor of N
N = N - (N / P) + P
while P != Z
return N - Z
А ось коментований вираз:
# \1 = largest prime factor of N
# Computed by repeatedly dividing N by its smallest factor
(?= ( (xx+) (?=\2+$) | x+ )+ )
(?=
# Main loop!
(
# \4 = N % \1, N -= \4
(x*?) (?=\1*$)
# \5 = next prime factor of N
(?= (\4xx+?) (\5* (?!(xx+)\7+$) \5)? $ )
# \8 = N / \5, \9 = \8 - 1, \10 = N - \8
(?= ((x*) (?=\5\9*$) x) (\8*) $ )
x*
(?=
# if \5 = \1, break.
(?=\5$) \1
|
# else, N = (\5 - 1) + (N - B)
\5\10
)
x
)+
) \10
І як бонус ...
Regex (ECMAScript 2018, кількість збігів), 23 байти
x(?<!^\1*(?=\1*$)(x+x))
Спробуйте в Інтернеті!
Вихід - кількість збігів. ECMAScript 2018 представляє перегляд відстані змінної довжини (оцінюється справа наліво), що дозволяє просто підраховувати всі числа одночасно з введенням.
Виявляється, це незалежно той самий метод, який застосовується в розчині Сітківки Лікі Нуна , і регулярний вираз навіть однакової довжини ( і взаємозамінний ). Я залишаю його тут, тому що це може бути цікавим, що цей метод працює в ECMAScript 2018 (і не тільки .NET).
# Implicitly iterate from the input to 0
x # Don’t match 0
(?<! ) # Match iff there is no...
(x+x) # integer >= 2...
(?=\1*$) # that divides the current number...
^\1* # and also divides the input