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);}}
(Một số dòng mới không được tính trong số byte đã được thêm ở trên để loại bỏ các thanh cuộn. Có, dòng mới cuối cùng được tính.)
Mong đợi các đối số trên dòng lệnh và giả sử đầu ra tiêu chuẩn chấp nhận ASCII. Thời gian chạy là O (số lượng đầu ra byte) = O (n * n).
Không, tôi không thể sử dụng printf
. Điều đó làm mất quá nhiều thời gian và đẩy chương trình vượt quá giới hạn phút trên máy tính để bàn của tôi. Như vậy, một số trường hợp thử nghiệm mất khoảng 30 giây.
Thuật toán coi đầu ra là các chuỗi, không phải là số, vì chúng nhanh chóng trở nên to lớn và có các mẫu mạnh trong đầu ra.
Hơi vô dụng:
#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;
}
}
}
}
Bằng chứng
chương trình giải quyết vấn đề:
(Trong bằng chứng, lấy tất cả các toán tử và hàm là các hàm toán học thực sự, không phải là các phép toán máy tính gần đúng với chúng. ^
Biểu thị lũy thừa, không phải là xor bitwise.)
Để rõ ràng, tôi sẽ sử dụng một hàm ToDec
để mô tả quá trình viết số thông thường dưới dạng một chuỗi các chữ số thập phân. Phạm vi của nó là tập hợp các bộ dữ liệu được đặt hàng trên {0...9}
. Ví dụ,
ToDec(2014) = (2, 0, 1, 4).
Đối với một số nguyên dương n
, xác định L(n)
là số chữ số trong biểu diễn thập phân của n
; hoặc là,
L(n) = 1+floor(log10(n)).
Đối với một số nguyên dương k
và một số nguyên không âm n
với L(n)<k
, hãy xác định Rep_k(n)
là số thực có được bằng cách thêm các số 0 ở trước các chữ số thập phân của n
, nếu cần để lấy k
tổng các chữ số, sau đó lặp lại vô hạn các k
chữ số đó sau dấu thập phân. Ví dụ
Rep_4(2014) = .201420142014...
Rep_5(2014) = .020140201402...
Nhân Rep_k(n) * 10^k
cho các chữ số n
trước dấu thập phân và chữ số (không đệm) được n
lặp lại vô hạn sau dấu thập phân. Vì thế
Rep_k(n) * 10^k = n + Rep_k(n)
Rep_k(n) = n / (10^k - 1)
Cho một số nguyên dương r
, giả sử x
là một giải pháp cho vấn đề và
ToDec(x) = ( x_1, x_2, ..., x_k )
ở đâu x_1 != 0
và k = L(x)
.
Là một giải pháp, x
là bội số của r
, và
ToDec(x/r) : ( x_2, x_3, ..., x_k, x_1 ).
Áp dụng Rep_k
hàm cho một phương trình tốt đẹp:
10*Rep_k(x) = x_1 + Rep_k(x/r)
Sử dụng hình thức đóng của nó từ phía trên,
10x / (10^k - 1) = x_1 + x / r / (10^k - 1)
x = x_1 * r * (10^k-1) / (10r - 1)
x_1
phải nằm trong bộ {1 ... 9}
. r
đã được chỉ định là trong tập hợp {2 ... 9}
. Bây giờ câu hỏi duy nhất là, với giá trị k
nào của công thức trên để x
cho một số nguyên dương? Chúng tôi sẽ xem xét từng giá trị có thể của r
cá nhân.
Khi r
= 2, 3, 6, 8 hoặc 9, lần lượt 10r-1
là 19, 29, 59, 79 hoặc 89. Trong mọi trường hợp, mẫu số p = 10r-1
là số nguyên tố. Trong tử số, chỉ 10^k-1
có thể là bội số p
, xảy ra khi
10^k = 1 (mod p)
Tập hợp các giải pháp được đóng dưới phép cộng và phép trừ không dẫn đến số âm. Vì vậy, tập hợp bao gồm tất cả các bội số của một số yếu tố phổ biến, cũng là giải pháp ít tích cực nhất cho k
.
Khi nào r = 4
và 10r-1 = 39
; hoặc khi r = 7
và 10r-1 = 69
, mẫu số là 3 lần một số nguyên tố khác nhau p=(10r-1)/3
. 10^k-1
luôn là bội số của 3 và một lần nữa, không có yếu tố nào khác trong tử số có thể là bội số của p
, do đó, một lần nữa vấn đề giảm xuống
10^k = 1 (mod p)
và một lần nữa các giải pháp là tất cả các bội số của giải pháp ít tích cực nhất cho k
.
[Chưa xong...]
gprof
, một trường hợp đầu vào cho chương trình của tôi dành ít hơn nửa giây trong mã của tôi, nhưng mất khoảng 80 giây, mà tôi cho rằng chủ yếu phải chặn đầu ra.