C 468
#include <stdlib.h>
#include <stdio.h>
#define a(s)fputs(s,stdout);
#define b(c)putchar(c);
int r;int z(char*s,int m){for(int i=0;i++<=m;)a(s)b(47)b(r+48)b(61)char*t=s;
while(*++t==48);a(t)while(m--)a(s)b(*s)b(10)}char x[10][60];
int main(int c,char**v){r=atoi(v[1]);int n=atoi(v[2]),q=10*r-1,d=0,p;
while(d++<9){p=r*d;char*y=x[d];do{p*=10;*y++=p/q+48;p%=q;}while(p!=r*d);}
d=1;p=q=0;while(n--){r==5&p<6?z(x[7],7*q+p++):(z(x[d],(r==5&d==7)?7*q+6:q),
++d>9?q+=d=1,p=0:0);}}
(Algunas líneas nuevas no contadas en el recuento de bytes se han agregado anteriormente para eliminar las barras de desplazamiento. Sí, se cuenta la línea nueva final).
Espera argumentos en la línea de comando y supone que la salida estándar acepta ASCII. El tiempo de ejecución es O (número de bytes de salida) = O (n * n).
No, no puedo usar printf. Eso lleva demasiado tiempo y empuja el programa por encima del límite de minutos en mi escritorio. Tal como están las cosas, algunos casos de prueba tardan unos 30 segundos.
El algoritmo trata la salida como cadenas, no números, ya que rápidamente se vuelven enormes, y hay patrones fuertes en la salida.
Algo sin golf:
#include <stdlib.h>
#include <stdio.h>
/* r is as in the problem description */
int r;
void show_line(const char* num, int repeats) {
for (int i=0; i <= repeats; ++i)
fputs(num, stdout);
printf("/%c=", '0'+r);
/* Assume the repeated num is a solution. Just move the first
digit and skip any resulting leading zeros. */
const char* num_tail = num;
++num_tail;
while (*num_tail=='0')
++num_tail;
fputs(num_tail, stdout);
while (repeats--)
fputs(num, stdout);
printf("%c\n", *num);
}
/* sol[0] is unused. Otherwise, sol[d] is the repeating digits in the
decimal representation of (r*d)/(10*r-1). */
char sol[10][60];
int main(int argc, char** argv) {
r = atoi(argv[1]);
int n = atoi(argv[2]);
int q = 10*r-1;
int d = 0;
/* Populate the strings in sol[]. */
while (d++<9) {
int p = r*d;
char* sol_str = sol[d];
/* Do the long division p/q in decimal, stopping when the remainder
is the original dividend. The integer part is always zero. */
do {
p *= 10;
*sol_str++ = p/q + '0';
p %= q;
} while (p != r*d);
}
/* Output the answers. */
d = 1;
int repeats = 0;
int r5x7_repeats = 0;
while (n--) {
if (r==5 && r5x7_repeats<6) {
show_line(x[7], 7*repeats + r5x7_repeats);
} else {
if (r==5 && d==7)
show_line(x[d], 7*repeats + 6);
else
show_line(x[d], repeats);
if (++d > 9) {
d = 1;
++repeats;
r5x7_repeats = 0;
}
}
}
}
Prueba
que el programa resuelve el problema:
(En la prueba, considere que todos los operadores y funciones son las funciones matemáticas reales, no las operaciones de la computadora que las aproximan. ^Denota exponenciación, no bit a xor).
Para mayor claridad, usaré una función ToDecpara describir el proceso ordinario de escribir un número como una secuencia de dígitos decimales. Su rango es el conjunto de tuplas ordenadas {0...9}. Por ejemplo,
ToDec(2014) = (2, 0, 1, 4).
Para un entero positivo n, defínalo L(n)como el número de dígitos en la representación decimal de n; o,
L(n) = 1+floor(log10(n)).
Para un entero positivo ky un entero no negativo ncon L(n)<k, defina Rep_k(n)como el número real obtenido agregando ceros delante de los dígitos decimales de n, si es necesario para obtener kdígitos totales, y luego repitiendo infinitamente esos kdígitos después del punto decimal. P.ej
Rep_4(2014) = .201420142014...
Rep_5(2014) = .020140201402...
Multiplicar Rep_k(n) * 10^kda los dígitos nanteriores al punto decimal, y los dígitos (rellenos con cero) de ninfinitamente repetidos después del punto decimal. Entonces
Rep_k(n) * 10^k = n + Rep_k(n)
Rep_k(n) = n / (10^k - 1)
Dado un número entero positivo r, supongamos que xes una solución al problema, y
ToDec(x) = ( x_1, x_2, ..., x_k )
donde x_1 != 0y k = L(x).
Para ser una solución, xes un múltiplo de ry
ToDec(x/r) : ( x_2, x_3, ..., x_k, x_1 ).
Aplicar la Rep_kfunción da una buena ecuación:
10*Rep_k(x) = x_1 + Rep_k(x/r)
Usando su forma cerrada desde arriba,
10x / (10^k - 1) = x_1 + x / r / (10^k - 1)
x = x_1 * r * (10^k-1) / (10r - 1)
x_1debe estar en el set {1 ... 9}. rse especificó para estar en el conjunto {2 ... 9}. Ahora la única pregunta es, ¿para qué valores de kla fórmula anterior xda un número entero positivo? Consideraremos cada valor posible de forma rindividual.
Cuando r= 2, 3, 6, 8 o 9, 10r-1es 19, 29, 59, 79 u 89, respectivamente. En todos los casos, el denominador p = 10r-1es primo. En el numerador, solo 10^k-1puede ser un múltiplo de p, lo que sucede cuando
10^k = 1 (mod p)
El conjunto de soluciones se cierra con sumas y restas que no resultan en un número negativo. Entonces, el conjunto comprende todos los múltiplos de algún factor común, que también es la solución menos positiva para k.
Cuando r = 4y 10r-1 = 39; o cuando r = 7y 10r-1 = 69, el denominador es 3 veces un primo diferente p=(10r-1)/3. 10^k-1siempre es un múltiplo de 3, y nuevamente ningún otro factor en el numerador puede ser múltiplo de p, por lo que nuevamente el problema se reduce a
10^k = 1 (mod p)
y nuevamente las soluciones son todos los múltiplos de la solución menos positiva para k.
[Sin terminar...]
gprof, un caso de entrada para mi programa pasa menos de medio segundo en mi código, pero toma alrededor de 80 segundos en total, lo que supongo que debe estar bloqueando la salida.