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);}}
(바이트 수로 계산되지 않은 일부 줄 바꿈이 스크롤 막대를 제거하기 위해 위에 추가되었습니다. 예, 마지막 줄 바꿈이 계산됩니다.)
명령 행에서 인수를 예상하고 표준 출력이 ASCII를 승인한다고 가정합니다. 런타임은 O (바이트 수 출력) = O (n * n)입니다.
아니요, 사용할 수 없습니다 printf
. 시간이 너무 많이 걸리고 바탕 화면의 분 단위로 프로그램을 푸시합니다. 그대로, 일부 테스트 케이스는 약 30 초가 걸립니다.
알고리즘은 출력이 빠르게 커지고 출력에 강한 패턴이 있기 때문에 출력을 숫자가 아닌 문자열로 처리합니다.
언 골프 :
#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;
}
}
}
}
증명
프로그램이 문제를 해결한다는 것을
(증거에서 모든 연산자와 함수를 근사한 컴퓨터 연산이 아니라 실제 수학 함수로 만듭니다. ^
비트 xor가 아닌 지수를 나타냅니다.)
명확하게하기 위해 함수 ToDec
를 사용 하여 숫자를 일련의 10 진수로 쓰는 일반적인 프로세스를 설명합니다. 범위는 정렬 된 튜플 세트입니다 {0...9}
. 예를 들어
ToDec(2014) = (2, 0, 1, 4).
양의 정수의 경우 소수점 이하 자릿수로 표시되는 자릿수로 n
정의 L(n)
하십시오 n
. 또는,
L(n) = 1+floor(log10(n)).
양의 정수 k
와 음이 아닌 정수 n
로 L(n)<k
정의 Rep_k(n)
의 십진수 앞에 0을 더한 실수로 n
얻기 위해 필요한 경우, k
숫자는 총 후 무한 그 반복 k
소수점 후 숫자. 예 :
Rep_4(2014) = .201420142014...
Rep_5(2014) = .020140201402...
곱 Rep_k(n) * 10^k
하면 n
소수점 앞의 자릿수와 n
소수점 다음 에 무한 반복되는 (0이 채워진) 자릿수가 표시 됩니다. 그래서
Rep_k(n) * 10^k = n + Rep_k(n)
Rep_k(n) = n / (10^k - 1)
양의 정수가 주어지면 문제에 대한 해결책 r
이라고 가정 x
하고
ToDec(x) = ( x_1, x_2, ..., x_k )
어디 x_1 != 0
에서 k = L(x)
.
해가 되려면의 x
배수 r
이며
ToDec(x/r) : ( x_2, x_3, ..., x_k, x_1 ).
이 Rep_k
함수를 적용하면 멋진 방정식이 나타납니다.
10*Rep_k(x) = x_1 + Rep_k(x/r)
위에서 닫힌 양식을 사용하여
10x / (10^k - 1) = x_1 + x / r / (10^k - 1)
x = x_1 * r * (10^k-1) / (10r - 1)
x_1
세트에 있어야합니다 {1 ... 9}
. r
세트에 있도록 지정되었습니다 {2 ... 9}
. 이제 유일한 질문은 k
위의 공식 중 어떤 값이 x
양의 정수 를 제공합니까? 우리는 각각의 가능한 모든 가치를 고려할 것 r
입니다.
경우 r
= 2, 3, 6, 8, 9, 10r-1
각각 19, 29, 59, 79, 또는 89이다. 모든 경우에 분모 p = 10r-1
가 가장 중요합니다. 분자에서, 단지 10^k-1
의 배수가 될 수 p
발생,
10^k = 1 (mod p)
덧셈과 뺄셈에서 음수를 나타내지 않는 솔루션 세트는 닫힙니다. 따라서이 집합은 공통 요소의 모든 배수로 구성되며에 대한 최소 양성 솔루션입니다 k
.
언제 r = 4
그리고 10r-1 = 39
; 또는 때 r = 7
와 10r-1 = 69
분모는 3 번 다른 주요이다 p=(10r-1)/3
. 10^k-1
는 항상 3의 배수이며 분자의 다른 요소는의 배수가 될 수 p
없으므로 다시 문제는
10^k = 1 (mod p)
다시 솔루션은에 대한 최소 양성 솔루션의 배수입니다 k
.
[완료되지 않았습니다 ...]
gprof
내 프로그램의 한 입력 사례가 코드에서 0.5 초 미만을 소비하지만 총 80 초가 걸리므로 출력에서 대부분 차단해야한다고 가정합니다.