Regex (ECMAScript), 131 bytes
Al menos -12 bytes gracias a Deadcode (en el chat)
(?=((xx+)(?=\2+$)|x+)+)(?=((x*?)(?=\1*$)(?=(\4xx+?)(\5*(?!(xx+)\7+$)\5)?$)(?=((x*)(?=\5\9*$)x)(\8*)$)x*(?=(?=\5$)\1|\5\10)x)+)\10|x
Pruébalo en línea!
La salida es la duración del partido.
Las expresiones regulares ECMAScript hacen que sea extremadamente difícil contar algo. Cualquier reflujo definido fuera de un bucle será constante durante el bucle, cualquier reflujo definido dentro de un bucle se restablecerá durante el bucle. Por lo tanto, la única forma de llevar el estado a través de iteraciones de bucle es usar la posición de coincidencia actual. Es un número entero único, y solo puede disminuir (bueno, la posición aumenta, pero la longitud de la cola disminuye, y eso es lo que podemos hacer con las matemáticas).
Dadas esas restricciones, simplemente contar los números coprimos parece imposible. En cambio, usamos la fórmula de Euler para calcular el totient.
Así es como se ve en pseudocódigo:
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
Hay dos cosas dudosas sobre esto.
Primero, no guardamos la entrada, solo el producto actual, entonces, ¿cómo podemos llegar a los factores primos de la entrada? El truco es que (N - (N / P)) tiene los mismos factores primos> P que N. Puede obtener nuevos factores primos <P, pero los ignoramos de todos modos. Tenga en cuenta que esto solo funciona porque iteramos sobre los factores primos de menor a mayor, de lo contrario fallaría.
En segundo lugar, tenemos que recordar dos números en las iteraciones de bucle (P y N, Z no cuenta ya que es constante), ¡y acabo de decir que era imposible! Afortunadamente, podemos mezclar esos dos números en uno solo. Tenga en cuenta que, al comienzo del ciclo, N siempre será un múltiplo de Z, mientras que P siempre será menor que Z. Por lo tanto, podemos recordar N + P y extraer P con un módulo.
Aquí está el pseudocódigo un poco más detallado:
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
Y aquí está la expresión regular comentada:
# \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
Y como un bono ...
Regex (ECMAScript 2018, número de coincidencias), 23 bytes
x(?<!^\1*(?=\1*$)(x+x))
Pruébalo en línea!
La salida es el número de coincidencias. ECMAScript 2018 presenta una retrospectiva de longitud variable (evaluada de derecha a izquierda), que hace posible contar simplemente todos los números coprimos con la entrada.
Resulta que este es independientemente el mismo método utilizado por la solución Retina de Leaky Nun , y la expresión regular es incluso de la misma longitud ( e intercambiable ). Lo dejo aquí porque puede ser interesante que este método funcione en ECMAScript 2018 (y no solo .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