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);}}
(Bayt sayımında sayılmayan bazı yeni satırlar, kaydırma çubuklarını ortadan kaldırmak için yukarıda eklenmiştir. Evet, son yeni satır sayılır.)
Komut satırındaki bağımsız değişkenleri bekler ve standart çıktının ASCII'yi kabul ettiğini varsayar. Çalışma zamanı O (bayt çıkış sayısı) = O (n * n).
Hayır, kullanamam printf
. Bu çok fazla zaman alıyor ve programı masaüstümdeki dakika sınırını zorluyor. Olduğu gibi, bazı test vakaları yaklaşık 30 saniye sürer.
Algoritma, çıktıyı sayı olarak değil, sayı olarak ele alır, çünkü hızla büyürler ve çıktıda güçlü desenler vardır.
Biraz soluksuz:
#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;
}
}
}
}
Kanıt
programın sorunu çözdüğünü:
(İspatta, tüm operatörleri ve işlevleri gerçek matematiksel işlevler olarak kabul edin, onlara yaklaşan bilgisayar işlemleri ^
değil. Bit ile xor değil, üstellemeyi belirtir.)
Anlaşılır olması için, ToDec
bir sayıyı ondalık basamak dizisi olarak sıradan yazma işlemini tanımlamak için bir işlev kullanacağım . Aralığı, sipariş edilen tuples setidir {0...9}
. Örneğin,
ToDec(2014) = (2, 0, 1, 4).
Pozitif bir tamsayı için n
, L(n)
ondalık gösterimindeki basamak sayısı olarak tanımlayın n
; veya,
L(n) = 1+floor(log10(n)).
Pozitif bir tamsayı k
ve n
ile negatif olmayan bir tamsayı için , eğer ondalık basamakların önüne sıfır ekleyerek , eğer toplam rakamları elde etmek için gerekirse sıfırlar ekleyerek elde edilen gerçek sayı olarak L(n)<k
tanımlayın ve daha sonra ondalık noktadan sonra bu basamakları sonsuz bir şekilde tekrarlayın . ÖrneğinRep_k(n)
n
k
k
Rep_4(2014) = .201420142014...
Rep_5(2014) = .020140201402...
Çarpma , ondalık noktadan Rep_k(n) * 10^k
önceki basamaklarını n
ve ondalık noktadan n
sonra sonsuz tekrarlanan (sıfır dolgulu) basamakları verir . Yani
Rep_k(n) * 10^k = n + Rep_k(n)
Rep_k(n) = n / (10^k - 1)
Olumlu bir tam sayı verildiğinde r
, varsayalım x
, soruna bir çözümdür ve
ToDec(x) = ( x_1, x_2, ..., x_k )
nerede x_1 != 0
ve k = L(x)
.
Bir çözüm olarak, x
bir katıdır r
ve
ToDec(x/r) : ( x_2, x_3, ..., x_k, x_1 ).
Rep_k
Fonksiyonu uygulamak hoş bir denklem verir:
10*Rep_k(x) = x_1 + Rep_k(x/r)
Yukarıdan kapalı formunu kullanarak,
10x / (10^k - 1) = x_1 + x / r / (10^k - 1)
x = x_1 * r * (10^k-1) / (10r - 1)
x_1
sette olmalıdır {1 ... 9}
. r
sette olduğu belirtildi {2 ... 9}
. Şimdi tek soru, k
yukarıdaki formülün hangi değerleri için x
pozitif bir tamsayı veriyor? Her olası değeri r
ayrı ayrı ele alacağız .
Zaman r
= 2, 3, 6, 8 ya da 9, 10r-1
sırası ile, 19, 29, 59, 79, ya da 89 olduğu. Her durumda payda p = 10r-1
asaldır. Payda, sadece 10^k-1
katları olabilir p
,
10^k = 1 (mod p)
Çözelti kümesi, negatif sayı ile sonuçlanmayan toplama ve çıkarma altında kapatılır. Bu yüzden küme, aynı zamanda en az pozitif çözüm olan bazı ortak faktörlerin tüm katlarını içerir k
.
Ne zaman r = 4
ve 10r-1 = 39
; veya r = 7
ve 10r-1 = 69
payda 3 kez farklı bir asal p=(10r-1)/3
. 10^k-1
her zaman 3'ün katlarıdır ve yine paydaki başka hiçbir faktör katları olamaz p
, bu yüzden sorun yine
10^k = 1 (mod p)
ve yine çözeltiler, en az pozitif çözeltinin katlarıdır k
.
[Bitmedi...]
gprof
, programım için bir giriş durumu kodumda yarım saniyeden daha az harcıyor, ancak toplamda yaklaşık 80 saniye sürüyor, ki bu da çoğunlukla çıktıda engelleme olması gerektiğini varsayıyor.