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).
nDefinieren 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 kund eine nicht negative Ganzzahl nmit 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)<kRep_k(n)nkk
Rep_4(2014) = .201420142014...
Rep_5(2014) = .020140201402...
Beim Multiplizieren werden Rep_k(n) * 10^kdie Ziffern nvor dem Dezimalpunkt und die (mit Nullen aufgefüllten) Ziffern nnach dem Dezimalpunkt unendlich wiederholt. So
Rep_k(n) * 10^k = n + Rep_k(n)
Rep_k(n) = n / (10^k - 1)
rAngenommen, eine positive ganze Zahl xist eine Lösung für das Problem, und
ToDec(x) = ( x_1, x_2, ..., x_k )
wo x_1 != 0und k = L(x).
Eine Lösung zu sein, xist ein Vielfaches von rund
ToDec(x/r) : ( x_2, x_3, ..., x_k, x_1 ).
Das Anwenden der Rep_kFunktion 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_1muss im Set sein {1 ... 9}. rwurde angegeben, um im Satz zu sein {2 ... 9}. Die Frage ist nun nur, für welche Werte kdie obige Formel xeine positive ganze Zahl ergibt. Wir werden jeden möglichen Wert reinzeln betrachten.
Wenn r= 2, 3, 6, 8 oder 9 ist, 10r-1ist 19, 29, 59, 79 bzw. 89. In allen Fällen ist der Nenner p = 10r-1Primzahl. Im Zähler 10^k-1kann 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 = 4und 10r-1 = 39; oder wann r = 7und 10r-1 = 69, der Nenner ist dreimal eine andere Primzahl p=(10r-1)/3. 10^k-1ist 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...]
gprofverbringt 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.