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);}}
(Einige Zeilenumbrüche, die nicht in der Byteanzahl gezählt wurden, wurden oben hinzugefügt, um Bildlaufleisten zu entfernen. Ja, die letzte Zeilenumbruch wird gezählt.)
Erwartet Argumente in der Befehlszeile und geht davon aus, dass die Standardausgabe ASCII akzeptiert. Die Laufzeit ist O (Anzahl der ausgegebenen Bytes) = O (n * n).
Nein, ich kann nicht verwenden printf
. Das dauert zu lange und schiebt das Programm über das Minutenlimit auf meinem Desktop. Einige Testfälle dauern ungefähr 30 Sekunden.
Der Algorithmus behandelt die Ausgabe als Zeichenfolgen und nicht als Zahlen, da sie schnell enorm werden und die Ausgabe starke Muster enthält.
Etwas ungolf:
#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;
}
}
}
}
Beweis
dass das Programm das Problem löst:
(Nehmen Sie im Beweis, dass alle Operatoren und Funktionen die realen mathematischen Funktionen sind, nicht die Computeroperationen, die sie approximieren. ^
Bezeichnet Exponentiation, nicht bitweises xor.)
Aus Gründen der Klarheit werde ich eine Funktion verwenden ToDec
, um den normalen Vorgang des Schreibens einer Zahl als Folge von Dezimalstellen zu beschreiben. Seine Reichweite ist die Menge der bestellten Tupel auf {0...9}
. Beispielsweise,
ToDec(2014) = (2, 0, 1, 4).
n
Definieren Sie für eine positive Ganzzahl L(n)
die Anzahl der Stellen in der Dezimaldarstellung von n
; oder,
L(n) = 1+floor(log10(n)).
Definieren Sie für eine positive Ganzzahl k
und eine nicht negative Ganzzahl n
mit die reelle Zahl, die durch Hinzufügen von Nullen vor den Dezimalstellen von , falls erforderlich, um die Gesamtzahl der Stellen zu erhalten , und anschließende unendliche Wiederholung dieser Stellen nach dem Dezimalpunkt erhalten wird. Z.BL(n)<k
Rep_k(n)
n
k
k
Rep_4(2014) = .201420142014...
Rep_5(2014) = .020140201402...
Beim Multiplizieren werden Rep_k(n) * 10^k
die Ziffern n
vor dem Dezimalpunkt und die (mit Nullen aufgefüllten) Ziffern n
nach dem Dezimalpunkt unendlich wiederholt. So
Rep_k(n) * 10^k = n + Rep_k(n)
Rep_k(n) = n / (10^k - 1)
r
Angenommen, eine positive ganze Zahl x
ist eine Lösung für das Problem, und
ToDec(x) = ( x_1, x_2, ..., x_k )
wo x_1 != 0
und k = L(x)
.
Eine Lösung zu sein, x
ist ein Vielfaches von r
und
ToDec(x/r) : ( x_2, x_3, ..., x_k, x_1 ).
Das Anwenden der Rep_k
Funktion ergibt eine schöne Gleichung:
10*Rep_k(x) = x_1 + Rep_k(x/r)
Mit seiner geschlossenen Form von oben,
10x / (10^k - 1) = x_1 + x / r / (10^k - 1)
x = x_1 * r * (10^k-1) / (10r - 1)
x_1
muss im Set sein {1 ... 9}
. r
wurde angegeben, um im Satz zu sein {2 ... 9}
. Die Frage ist nun nur, für welche Werte k
die obige Formel x
eine positive ganze Zahl ergibt. Wir werden jeden möglichen Wert r
einzeln betrachten.
Wenn r
= 2, 3, 6, 8 oder 9 ist, 10r-1
ist 19, 29, 59, 79 bzw. 89. In allen Fällen ist der Nenner p = 10r-1
Primzahl. Im Zähler 10^k-1
kann nur ein Vielfaches von sein p
, was passiert, wenn
10^k = 1 (mod p)
Der Satz von Lösungen wird unter Addition und unter Subtraktion geschlossen, was nicht zu einer negativen Zahl führt. Die Menge umfasst also alle Vielfachen eines gemeinsamen Faktors, was auch die am wenigsten positive Lösung für ist k
.
Wann r = 4
und 10r-1 = 39
; oder wann r = 7
und 10r-1 = 69
, der Nenner ist dreimal eine andere Primzahl p=(10r-1)/3
. 10^k-1
ist immer ein Vielfaches von 3, und wieder kann kein anderer Faktor im Zähler ein Vielfaches von sein p
, so dass sich das Problem wieder auf reduziert
10^k = 1 (mod p)
und wieder sind die Lösungen alle Vielfachen der am wenigsten positiven Lösung für k
.
[Nicht beendet...]
gprof
verbringt ein Eingabefall für mein Programm weniger als eine halbe Sekunde in meinem Code, dauert aber insgesamt etwa 80 Sekunden, von denen ich annehme, dass sie die Ausgabe größtenteils blockieren.