Dati r e n, trova i primi n numeri di x dove spostando la prima cifra di x per ultimo si ottiene x / r = y


11

Obbiettivo

Dato input re ntrova i primi nnumeri naturali in modo xtale che se ruotiamo la prima cifra nell'ultima posizione otteniamo x/r.

Puoi presumere che 2 <= r <= 9e 1 <= n <= 65535.

È possibile scrivere un programma che accetta input dagli argomenti stdin o della riga di comando; oppure puoi scrivere una funzione che accetta re ncome parametri. L'output, tuttavia, dovrebbe essere stdout. L'output deve essere una riga per valore di x, formattato come x/r=y, in ordine crescente x.

La soluzione deve essere in grado di gestire tutti i casi validi entro un minuto su un computer desktop ragionevole.

Casi test

Ingresso: 4 5
Uscita:

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

Ingresso: 5 1
Uscita:714285/5=142857

Questo è code-golf, quindi vincono meno byte. La risposta vincente sarà accettata tra 4 settimane (19/09/2014).

I crediti per questa domanda vanno al mio collega, che mi ha permesso di pubblicare questa domanda qui :)


Il limite di tempo è difficile con la quantità di output richiesta. Secondo gprof, un caso di input per il mio programma spende meno di mezzo secondo nel mio codice, ma impiega circa 80 secondi in totale, che presumo debba essere principalmente bloccato sull'output.
aschepler,

Ah, l'ho evitato evitando printf.
aschepler,

Risposte:


7

Haskell, 182 179

Seconda versione, probabilmente ulteriormente giocabile a golf, ma con algoritmo "corretto" questa volta. In particolare, termina in pochi minuti con r=4e n=65535, ma poi il mio computer non è né ragionevole né desktop, quindi è probabile che rimanga entro un minuto su altre macchine.

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

Si basa sull'idea che x=10^k*a + m, dove la sua prima cifra 0≤a≤9viene spostata alla fine per ottenere y=10*m+a. Un po matematica rivela che mpossono essere ottenuti come a*(10^k-r)/(10*r-1), in modo da esplorare semplicemente asopra [1..9]indipendentemente dai kda 0 a infinito, e mantenere e stampare i primi nrisultati per i quali l'espressione sopra per mcentrale integrale.

Ciò fromIntegralè necessario perché la readcreazione di un elenco ncome uno dei suoi elementi in main, in combinazione con l'uso di nin take, forzerebbe ra Inttutto, il che si traduce in brutti trabocchi con i grandi numeri in questione. Avrei potuto usare genericTake, ma questo richiede un import.

Questo codice ha anche il vantaggio di essere quasi banale per espandersi su basi diverse da 10.

L'input viene letto da stdin, i due valori possono essere separati da qualsiasi spazio bianco.


Il tuo codice dovrebbe essere più breve se ti sbarazzi delle backstick
orgoglioso haskeller il

@proudhaskeller: non sono sicuro perché non ci sono parentesi attorno a loro per separare operatore e operando senza richiedere spazi.
TheSpanishInquisition

Non riesco a leggere Haskell, quindi non sono del tutto sicuro di quello che stai facendo. Questo risolverà r = 5; n = 65535entro un minuto?
Martin Ender,

@ MartinBüttner: stavo aspettando quel commento. Sì, probabilmente lo farà, ma non sul mio computer (o chiunque altro in questo momento, in effetti). Il problema richiede un algoritmo più avanzato, credo. :(
TheSpanishInquisition,

@TheSpanishInquisition Ma ahould in grado di sostituire y`mod`10con mod y10, che è un carattere più breve
haskeller orgogliosi

1

Pure Bash (senza utility esterne), 80 byte

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

Nota bash fa solo l'aritmetica dei numeri interi e non il virgola mobile, quindi controlliamo se x == y * rinvece di x / r == y. Anche la moltiplicazione dovrebbe essere generalmente più veloce. Tuttavia, questo non è affatto vicino a soddisfare i requisiti di prestazione.

Produzione:

$ ./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);}}

(Alcune nuove righe non conteggiate nel conteggio byte sono state aggiunte sopra per eliminare le barre di scorrimento. Sì, viene conteggiata la nuova riga finale.)

Si aspetta argomenti dalla riga di comando e presuppone che l'output standard accetti ASCII. Il tempo di esecuzione è O (numero di byte in uscita) = O (n * n).

No, non posso usare printf. Ciò richiede troppo tempo e spinge il programma oltre il limite dei minuti sul mio desktop. Allo stato attuale, alcuni casi di test impiegano circa 30 secondi.

L'algoritmo tratta l'output come stringhe, non numeri, poiché diventano rapidamente enormi e ci sono modelli forti nell'output.

Abbastanza ungolfed:

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

Prova

che il programma risolva il problema:

(Nella dimostrazione, considera tutti gli operatori e le funzioni come le vere funzioni matematiche, non le operazioni del computer che le avvicinano. ^Denota esponenziazione, non xor bit a bit.)

Per chiarezza, userò una funzione ToDecper descrivere il normale processo di scrittura di un numero come una sequenza di cifre decimali. La sua gamma è l'insieme delle tuple ordinate {0...9}. Per esempio,

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

Per un numero intero positivo n, definire L(n)il numero di cifre nella rappresentazione decimale di n; o,

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

Per un numero intero positivo ke un numero intero non negativo ncon L(n)<k, definire Rep_k(n)come il numero reale ottenuto aggiungendo zeri prima delle cifre decimali di n, se necessario per ottenere il ktotale delle cifre, quindi ripetere ripetutamente quelle kcifre dopo il punto decimale. Per esempio

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

La moltiplicazione Rep_k(n) * 10^kindica le cifre nprima del punto decimale e le cifre (con zero) di ninfinito ripetute dopo il punto decimale. Così

Rep_k(n) * 10^k = n + Rep_k(n)
Rep_k(n) = n / (10^k - 1)

Dato un numero intero positivo r, supponiamo che xsia una soluzione al problema e

ToDec(x) = ( x_1, x_2, ..., x_k )

dove x_1 != 0e k = L(x).

Per essere una soluzione, xè un multiplo di re

ToDec(x/r) : ( x_2, x_3, ..., x_k, x_1 ).

L'applicazione della Rep_kfunzione fornisce una bella equazione:

10*Rep_k(x) = x_1 + Rep_k(x/r)

Usando la sua forma chiusa dall'alto,

10x / (10^k - 1) = x_1 + x / r / (10^k - 1)
x = x_1 * r * (10^k-1) / (10r - 1)

x_1deve essere nel set {1 ... 9}. rè stato specificato per essere nel set {2 ... 9}. Ora l'unica domanda è: per quali valori della kformula precedente si ottiene xun numero intero positivo? Prenderemo in considerazione ogni possibile valore di rindividualmente.

Quando r= 2, 3, 6, 8 o 9, 10r-1è rispettivamente 19, 29, 59, 79 o 89. In tutti i casi, il denominatore p = 10r-1è primo. Nel numeratore, solo 10^k-1può essere un multiplo di p, che succede quando

10^k = 1 (mod p)

L'insieme di soluzioni viene chiuso in aggiunta e in sottrazione che non comporta un numero negativo. Quindi l'insieme comprende tutti i multipli di qualche fattore comune, che è anche la soluzione meno positiva per k.

Quando r = 4e 10r-1 = 39; o quando r = 7e 10r-1 = 69, il denominatore è 3 volte un numero primo diverso p=(10r-1)/3. 10^k-1è sempre un multiplo di 3, e di nuovo nessun altro fattore nel numeratore può essere un multiplo di p, quindi il problema si riduce a

10^k = 1 (mod p)

e ancora una volta le soluzioni sono tutti i multipli della soluzione meno positiva per k.

[Non finito...]


0

Python - 91 90

Ecco un primo colpo:

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

Modifica: Ok, probabilmente è un modo per rallentare per rispettare il limite di 1 minuto richiesto per i numeri di 65K.


1
Hai provato questo rispetto ai requisiti di prestazione?
Peter Taylor,

2
Ho i miei dubbi sul fatto che questo troverà 65.000 di tali numeri prima che esploda il sole.
Martin Ender,

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

non golfato:

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

Non riesco affatto a farlo funzionare, ma anche se lo facesse, dubito che soddisferebbe i requisiti di prestazione.
Martin Ender,

@ MartinBüttner funziona perfettamente per me. è possibile che non soddisfi i requisiti di prestazione, ma il computer che sono in questo momento è piuttosto debole ... Cosa hai fatto per far funzionare questo pezzo di codice?
Armin,

1
L'ho copiato nella console e aggiunto (5,4). Il motivo per cui non funzionerà è che i numeri diventano molto grandi. a) Molto più grande di un numero in JS può rappresentare con precisione eb) troppo grande in quanto sarebbe possibile scorrere tutti i numeri per arrivarci.
Martin Ender,

0

Python 3 - 223 179 byte

Implementazione Python della soluzione di TheSpanishInquisition:

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

Correre:

  • python3 <whatever you named it>.py
  • Accetta input su stdin
  • Spazio di input separato

Produzione:

$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

I risultati:

https://oeis.org/A092697 è il primo valore per ogni r.

Sembra che solo alcuni valori di k producano risposte e che l'intervallo sia regolare. Ad esempio per 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]

Gli intervalli sono:

  • 2 = 18
  • 3 = 28
  • 4 = 6
  • 5 = 6 (5 sembra essere un'anomalia, poiché per la maggior parte dei valori di r, ci sono gruppi di 9, 5 moduli gruppi di 9 e 1 (con solo a = 7 funzionante), vedi sotto)
  • 6 = 58
  • 7 = 22
  • 8 = 13
  • 9 = 44

Questo forma https://oeis.org/A094224 .

Utilizzando questi valori, è possibile creare una versione più efficiente:

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)

Tuttavia, non posso (ancora) dimostrare che questo continua matematicamente.

Risultati per 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
L'hai provato con l'input 9 65535?
Peter Taylor,

Probabilmente dovrei usarlo unsigned long longper farlo e renderlo multicore per farlo in un minuto.
matsjoyce,

1
Se unsigned long longè 64 bit, non è abbastanza grande.
Peter Taylor,

È vero, sono passato alla soluzione di @ TheSpanishInquisition e ho usato invece Python.
matsjoyce,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.