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);}}
(Beberapa baris baru yang tidak dihitung dalam jumlah byte telah ditambahkan di atas untuk menghilangkan bilah gulir. Ya, baris akhir terakhir dihitung.)
Mengharapkan argumen pada baris perintah, dan mengasumsikan output standar menerima ASCII. Runtime adalah O (jumlah byte keluaran) = O (n * n).
Tidak, saya tidak bisa menggunakan printf
. Itu membutuhkan terlalu banyak waktu dan mendorong program melebihi batas menit pada desktop saya. Karena itu, beberapa kasus uji memerlukan waktu sekitar 30 detik.
Algoritma memperlakukan output sebagai string, bukan angka, karena mereka dengan cepat menjadi sangat besar, dan ada pola yang kuat dalam output.
Agak tidak terserang:
#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;
}
}
}
}
Bukti
bahwa program menyelesaikan masalah:
(Dalam buktinya, anggap semua operator dan fungsi sebagai fungsi matematika yang sebenarnya, bukan operasi komputer yang memperkirakannya. ^
Menunjukkan eksponensial, bukan bitwise xor.)
Untuk lebih jelasnya, saya akan menggunakan fungsi ToDec
untuk menggambarkan proses biasa menulis angka sebagai urutan angka desimal. Kisarannya adalah himpunan tupel yang dipesan {0...9}
. Sebagai contoh,
ToDec(2014) = (2, 0, 1, 4).
Untuk bilangan bulat positif n
, tentukan L(n)
menjadi jumlah digit dalam representasi desimal n
; atau,
L(n) = 1+floor(log10(n)).
Untuk bilangan bulat positif k
dan integer non-negatif n
dengan L(n)<k
, menentukan Rep_k(n)
untuk menjadi nomor nyata diperoleh dengan menambahkan angka nol di depan angka desimal n
, jika perlu untuk mendapatkan k
angka total, dan kemudian jauh mengulangi mereka k
digit setelah titik desimal. Misalnya
Rep_4(2014) = .201420142014...
Rep_5(2014) = .020140201402...
Mengalikan Rep_k(n) * 10^k
memberi angka n
sebelum titik desimal, dan (nol-empuk) angka n
diulang tak terbatas setelah titik desimal. Begitu
Rep_k(n) * 10^k = n + Rep_k(n)
Rep_k(n) = n / (10^k - 1)
Diberikan bilangan bulat positif r
, anggaplah x
solusi untuk masalah, dan
ToDec(x) = ( x_1, x_2, ..., x_k )
dimana x_1 != 0
dan k = L(x)
.
Untuk menjadi solusi, x
adalah kelipatan dari r
, dan
ToDec(x/r) : ( x_2, x_3, ..., x_k, x_1 ).
Menerapkan Rep_k
fungsi memberikan persamaan yang bagus:
10*Rep_k(x) = x_1 + Rep_k(x/r)
Menggunakan formulir tertutup dari atas,
10x / (10^k - 1) = x_1 + x / r / (10^k - 1)
x = x_1 * r * (10^k-1) / (10r - 1)
x_1
harus di set {1 ... 9}
. r
ditentukan berada di set {2 ... 9}
. Sekarang satu-satunya pertanyaan adalah, untuk nilai apa k
rumus di atas untuk x
memberikan bilangan bulat positif? Kami akan mempertimbangkan setiap nilai yang mungkin secara r
individual.
Ketika r
= 2, 3, 6, 8, atau 9, masing-masing 10r-1
adalah 19, 29, 59, 79, atau 89. Dalam semua kasus, penyebutnya p = 10r-1
prima. Dalam pembilang, hanya 10^k-1
bisa kelipatan p
, yang terjadi saat
10^k = 1 (mod p)
Himpunan solusi ditutup dengan penambahan dan pengurangan yang tidak menghasilkan angka negatif. Jadi himpunan terdiri dari semua kelipatan dari beberapa faktor umum, yang juga merupakan solusi paling positif untuk k
.
Kapan r = 4
dan 10r-1 = 39
; atau kapan r = 7
dan 10r-1 = 69
, penyebutnya 3 kali prima yang berbeda p=(10r-1)/3
. 10^k-1
selalu merupakan kelipatan 3, dan sekali lagi tidak ada faktor lain dalam pembilang yang bisa kelipatan p
, jadi sekali lagi masalahnya berkurang menjadi
10^k = 1 (mod p)
dan sekali lagi solusinya adalah kelipatan dari solusi paling tidak positif untuk k
.
[Belum selesai...]
gprof
, satu kasus input untuk program saya menghabiskan kurang dari setengah detik dalam kode saya, tetapi membutuhkan total sekitar 80 detik, yang saya anggap sebagian besar harus memblokir output.