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, ToDecbir 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ı kve nile 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)<ktanımlayın ve daha sonra ondalık noktadan sonra bu basamakları sonsuz bir şekilde tekrarlayın . ÖrneğinRep_k(n)nkk
Rep_4(2014) = .201420142014...
Rep_5(2014) = .020140201402...
Çarpma , ondalık noktadan Rep_k(n) * 10^könceki basamaklarını nve ondalık noktadan nsonra 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 != 0ve k = L(x).
Bir çözüm olarak, xbir katıdır rve
ToDec(x/r) : ( x_2, x_3, ..., x_k, x_1 ).
Rep_kFonksiyonu 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_1sette olmalıdır {1 ... 9}. rsette olduğu belirtildi {2 ... 9}. Şimdi tek soru, kyukarıdaki formülün hangi değerleri için xpozitif bir tamsayı veriyor? Her olası değeri rayrı ayrı ele alacağız .
Zaman r= 2, 3, 6, 8 ya da 9, 10r-1sırası ile, 19, 29, 59, 79, ya da 89 olduğu. Her durumda payda p = 10r-1asaldır. Payda, sadece 10^k-1katları 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 = 4ve 10r-1 = 39; veya r = 7ve 10r-1 = 69payda 3 kez farklı bir asal p=(10r-1)/3. 10^k-1her 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.