给定r和n,找到x的前n个数字,其中x的第一个数字移动到最后一个给出x / r = y


11

目的

给定输入rn找到第一个n自然数,x这样,如果我们将第一个数字旋转到最后一位,就可以得到x/r

您可以假设2 <= r <= 91 <= n <= 65535

您可以编写一个程序,该程序从stdin或命令行参数获取输入。或者您可以编写一个以rn作为参数的函数。但是,输出应为stdout。输出应为每个值的一行x,格式为x/r=y,按递增顺序x

您的解决方案必须能够在一台合理的台式计算机上在一分钟内处理所有有效案件。

测试用例

输入:4 5
输出:

102564/4=25641  
205128/4=51282  
307692/4=76923  
410256/4=102564  
512820/4=128205

输入:5 1
输出:714285/5=142857

这是代码高尔夫球,因此最少字节获胜。从现在开始(2014-09-19)4周将接受获奖答案。

这个问题的功劳归我的同事,他允许我在这里发布这个问题:)


时间限制对所需的输出量很严格。根据gprof,我的程序的一种输入情况在我的代码中花费的时间不到半秒,但是总共花费了大约80秒,我认为这在输出中主要是阻塞的。
aschepler 2014年

啊,我避开了它printf
aschepler 2014年

Answers:


7

哈斯克尔,182 179

第二个版本,可能更适用于高尔夫,但这次使用“适当”算法。特别是,它用r=4和会在几分钟之内完成n=65535,但随后我的计算机又再也不是台式机了,因此在其他计算机上一分钟之内就可以完成。

n#r=take n$[s(10^k*a+d)++'/':s r++'=':s d++s a|k<-[0..],a<-[1..9],let(d,m)=divMod(a*(10^k-r))(10*r-1),m<1]
s=show
main=interact$unlines.(\(r:n:_)->n#fromIntegral r).map read.words

它基于这样的思想,即将x=10^k*a + m其第一个数字0≤a≤9移到末尾以获得y=10*m+a。一个小的数学显示,m可以作为获得a*(10^k-r)/(10*r-1)的,所以我们简单地扫描a[1..9]k从0到无穷大,并保持和打印第一n结果这对于上述表达式m是一体的。

fromIntegral之所以需要,是因为将以in作为其元素之一的read列表与结合使用in 会强制执行整个操作,从而导致所讨论的大数字令人讨厌地溢出。我本来可以用的,但这需要一个。nmainntakerIntgenericTakeimport

该代码的优势还在于几乎可以轻松扩展到10以外的基数。

从中读取输入stdin,这两个值可以用任何空格分隔。


如果您摆脱了后盾,您的代码应该更短
骄傲的haskeller 2014年

@proudhaskeller:不确定,因为它们之间没有括号,以分隔运算符和操作数而无需空格。
TheSpanishInquisition

我看不懂Haskell,所以我不确定自己在做什么。r = 5; n = 65535一分钟内能解决吗?
Martin Ender 2014年

@MartinBüttner:我正在等待那条评论。是的,它可能会,但是不会在我的计算机上(实际上,或者在其他任何人的计算机上)。我认为该问题需要更高级的算法。:(
TheSpanishInquisition

@TheSpanishInquisition但您应该可以将替换y`mod`10mod y10,这是一个较短的字符
骄傲的haskeller 2014年

1

纯Bash(无外部实用程序),80字节

for((;++x,c<$2;));{
y=$[10#${x:1}${x:0:1}]
((y*$1==x))&&echo $x/$1=$y&&((c++))
}

请注意,bash仅执行整数算术运算,而不执行浮点运算,因此我们检查x == y * r而不是x / r == y。同样,乘法通常应该更快。不过,这远远不能满足性能要求。

输出:

$ ./rotdiv.sh 4 5
102564/4=25641
205128/4=51282
307692/4=76923
410256/4=102564
512820/4=128205
$ ./rotdiv.sh 5 1
714285/5=142857
$ 

1

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;
            }
        }
    }
}

证明

该程序解决了问题:

(在证明中,将所有运算符和函数视为真实的数学函数,而不是近似于它们的计算机运算。 ^表示幂运算,而不是按位异或。)

为了清楚起见,我将使用一个函数ToDec来描述将数字写为十进制数字序列的一般过程。其范围是上有序元组的集合{0...9}。例如,

ToDec(2014) = (2, 0, 1, 4).

对于正整数n,定义L(n)为十进制表示中的数字位数n; 要么,

L(n) = 1+floor(log10(n)).

为正整数k和非负整数nL(n)<k,定义Rep_k(n)为通过在的十进制数字前面添加零获得的实数n,如果有必要获得k数字总,然后无限重复那些k小数点后的数字。例如

Rep_4(2014) = .201420142014...
Rep_5(2014) = .020140201402...

乘法Rep_k(n) * 10^k给出n小数点前的数字,而n小数点后无限重复的(零填充)数字。所以

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 != 0k = 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被指定为set中的{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 = 410r-1 = 39; 或当r = 7和时10r-1 = 69,分母是不同素数的3倍p=(10r-1)/310^k-1始终是3的倍数,并且分子中的其他任何因素都不能是的倍数p,因此问题再次变为

10^k = 1 (mod p)

再次,解是最小正解的倍数k

[没做完...]


0

蟒蛇-91 90

这是第一枪:

r,n=input();i=1
while n:
 if int(`i`[1:]+`i`[0])*r==i:print'%d/%d=%d'%(i,r,i/r);n-=1
 i+=1

编辑:好的,这可能是慢速达到65K数字所需的1分钟时间限制的方法。


1
您是否已针对性能要求对此进行了测试?
彼得·泰勒

2
我怀疑在太阳爆炸之前是否会发现65k这样的数字。
马丁·恩德

0

JavaScript-145

function f(a,b){for(d=0;d<b;d++)for(i=1;;i++){c=i/a;if(c==parseInt(i.toString().substring(1)+i.toString().charAt(0)))console.log(i+'/'+a+'='+c)}}

不打高尔夫球:

function f(a,b){
    for(d=0;d<b;d++) //loop for the right amount
        for(i=1;;i++){ //iterating loop
            c=i/a; //actual result of the division
            if(c==parseInt(i.toString().substring(1)+i.toString().charAt(0)))
                console.log(i+'/'+a+'='+c)
        }
}

我根本无法使它正常工作,但是即使可以,我怀疑它能否满足性能要求。
马丁·恩德

@MartinBüttner,对我来说效果很好。可能是它不满足性能要求,但是我现在使用的计算机非常薄弱……您是如何使这段代码起作用的?
阿明2014年

1
将其复制到控制台并附加(5,4)。它无法正常工作的原因是数字会变得非常大。a)比JS中的数字大很多可以准确表示b)太大了,因为迭代所有数字到达那里是可行的。
马丁·恩德

0

Python的3 - 223个 179字节

TheSpanishInquisition解决方案的Python实现:

r,n=map(int,input().split());k=0
while 1:
 for a in range(1,10):
  D,M=divmod(a*(10**k-r),10*r-1)
  if M==0:
   print("%d/%d=%d"%(a*10**k+D,r,10*D+a));n-=1
   if n==0:exit()
 k+=1

跑:

  • python3 <whatever you named it>.py
  • 在stdin上接受输入
  • 输入空间分隔

输出:

$python3 <whatever you named it>.py
4 8
102564/4=25641
205128/4=51282
307692/4=76923
410256/4=102564
512820/4=128205
615384/4=153846
717948/4=179487
820512/4=205128

发现:

https://oeis.org/A092697是每个r的第一个值。

似乎只有k的某些值会产生答案,并且间隔是规则的。例如r = 4:

Form: k [a, a, ...]
0 []
1 []
2 []
3 []
4 []
5 [1, 2, 3, 4, 5, 6, 7, 8, 9]
6 []
7 []
8 []
9 []
10 []
11 [1, 2, 3, 4, 5, 6, 7, 8, 9]
12 []
13 []
14 []
15 []
16 []
17 [1, 2, 3, 4, 5, 6, 7, 8, 9]
18 []
19 []
20 []
21 []
22 []
23 [1, 2, 3, 4, 5, 6, 7, 8, 9]

间隔为:

  • 2 = 18
  • 3 = 28
  • 4 = 6
  • 5 = 6(5似乎是一个异常,至于r的大多数值,有9个团块,5个形式的团块9和1(只有a = 7起作用),请参见下文)
  • 6 = 58
  • 7 = 22
  • 8 = 13
  • 9 = 44

形成https://oeis.org/A094224

使用这些值,可以构建更有效的版本:

import math

def A094224(n):
    return [18,28,6,6,58,22,13,44][n-2]


r,n=map(int,input().split());k=A094224(r)-1
H={}
while 1:
    for a in range(1,10):
        D,M=divmod(a*10**k-a*r,10*r-1)
        if M==0:
            print("%d/%d=%d"%(a*10**k+D,r,10*D+a));n-=1
            if n==0:exit()
    k+=A094224(r)

但是,我(尚未)无法证明这一点在数学上仍在继续。

r = 5的结果:

0 []
1 []
2 []
3 []
4 []
5 [7]
6 []
7 []
8 []
9 []
10 []
11 [7]
12 []
13 []
14 []
15 []
16 []
17 [7]
18 []
19 []
20 []
21 []
22 []
23 [7]
24 []
25 []
26 []
27 []
28 []
29 [7]
30 []
31 []
32 []
33 []
34 []
35 [7]
36 []
37 []
38 []
39 []
40 []
41 [1, 2, 3, 4, 5, 6, 7, 8, 9]

2
你用输入测试了9 65535吗?
彼得·泰勒

我可能应该使用unsigned long long它,并使其在一分钟内成为多核。
matsjoyce 2014年

1
如果unsigned long long是64位,则不够大。
彼得·泰勒

是的,我已经切换到@TheSpanishInquisition的解决方案,而是使用了python。
matsjoyce 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.