rとnが与えられた場合、xの最初の数字を最後に移動するとx / r = yになるxの最初のn個の数字を見つける


11

目的

入力が与えられ、最初の自然数rn見つけて、最初の数字を最後の位置に回転させるとが得られます。nxx/r

あなたはそれ2 <= r <= 9と仮定するかもしれません1 <= n <= 65535

stdinまたはコマンドライン引数から入力を受け取るプログラムを作成できます。または、パラメータを取りrnパラメータとして使用する関数を作成できます。ただし、出力は標準出力にする必要があります。出力はの値ごとに1行であるべきであり、増加する順番にxフォーマットされx/r=yていxます。

ソリューションは、妥当なデスクトップコンピューターで1分以内にすべての有効なケースを処理できる必要があります。

テストケース

入力:4 5
出力:

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

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

これはコードゴルフであるため、最小バイトが勝ちます。勝利の答えは、今から4週間後に受け入れられます(2014-09-19)。

この質問のクレジットは同僚に送られ、同僚がこの質問をここに投稿することができました:)


時間制限は、必要な出力の量に対して厳しいです。によるとgprof、私のプログラムの1つの入力ケースはコードで0.5秒未満しか費やしませんが、合計で約80秒かかります。
アシェプラー14

ああ、私は回避してそれを回避しましたprintf
アシェプラー14

回答:


7

ハスケル、182 179

2番目のバージョンは、おそらくさらにゴルフ可能ですが、今回は「適切な」アルゴリズムを使用しています。特に、それは、と数分以内に終了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)ので、0から無限まですべてを単純にスキャンaし、上記の式が積分である最初の結果を保持して出力します。[1..9]knm

fromIntegralが必要なのは、その要素の1つとしてinを使用して、in の使用と組み合わせてreadリストを作成すると、強制的に全体が強制され、その結果、問題の大きな数字で厄介なオーバーフローが発生するためです。私は使用できたかもしれませんが、それにはが必要です。nmainntakerIntgenericTakeimport

このコードには、10以外のベースに拡張するのがほとんど簡単であるという利点もあります。

入力はから読み取られstdin、2つの値は任意の空白文字で区切ることができます。


バックスティックを削除する場合、コードは短くする必要があります
誇りに思ってhaskeller 14

@proudhaskeller:演算子とオペランドをスペースを必要とせずに分離するための括弧がないため、わかりません。
TheSpanishInquisition 14

Haskellを読むことができないので、あなたが何をしているのか完全にはわかりません。これr = 5; n = 65535は1分以内に解決しますか?
マーティンエンダー14

@MartinBüttner:そのコメントを待っていました。はい、おそらくそうなりますが、私のコンピューター(または、実際のところ、他の誰かの現在)ではそうではありません。問題には、より高度なアルゴリズムが必要だと思います。:(
TheSpanishInquisition 14

@TheSpanishInquisitionしかし、あなたは置き換えることができるahould y`mod`10mod y10短い文字である、
誇りhaskellerは

1

Pure 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。これには時間がかかりすぎて、プログラムがデスクトップの1分制限を超えてしまいます。現状では、一部のテストケースには約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)10進表現の桁数になるように定義します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セットにあるように指定されました{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 = 710r-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
これをパフォーマンス要件に対してテストしましたか?
ピーターテイラー14

2
太陽が爆発する前に、これで65kの数字が見つかるのではないかと思います。
マーティンエンダー14

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

私はこれをまったく動作させることはできませんが、たとえ動作したとしても、パフォーマンス要件を満たしているとは思えません。
マーティンエンダー14

@MartinBüttnerそれは私にとって完璧に動作します。パフォーマンス要件を満たしていない可能性がありますが、私が現在いるコンピューターはかなり弱いです...このコードを機能させるために何をしましたか?
アーミン14

1
コンソールにコピーして追加しました(5,4)。機能しない理由は、数が非常に大きくなるためです。a)JSの数値よりもはるかに大きいものは正確に表すことができ、b)そこに到達するためにすべての数値を反復処理するのが現実的であるほど大きすぎる。
マーティンエンダー14

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
  • 標準入力を入力します
  • 分離された入力スペース

出力:

$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の塊があります。
  • 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か?
ピーターテイラー14

私はおそらくそのために使用unsigned long longし、それを1分でマルチコアにする必要があります。
matsjoyce 14

1
場合はunsigned long long64ビットであり、それは大きな十分ではありません。
ピーターテイラー14

確かに、@ TheSpanishInquisitionのソリューションに切り替えて、代わりにpythonを使用しました。
matsjoyce 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.