З огляду на r і n, знайдіть перші n чисел x, коли переміщення першої цифри x до останньої дає x / r = y


11

Об'єктивна

Дано вхід rі nзнайдемо перші nнатуральні числа xтакі, що якщо повернути першу цифру до останнього місця, ми отримаємо x/r.

Ви можете припустити, що 2 <= r <= 9і 1 <= n <= 65535.

Ви можете написати програму, яка приймає дані з аргументів stdin або командного рядка; або ви можете написати функцію, яка приймає rі nяк параметри. Вихід, однак, повинен бути 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

Це код-гольф, тому виграйте найменше байт. Переможна відповідь буде прийнята через 4 тижні (2014-09-19).

Кредити на це питання дістаються моєму колезі, який дозволив мені опублікувати це питання тут :)


Обмеження в часі жорстке з необхідним обсягом продукції. Відповідно gprof, один випадок введення для моєї програми витрачає менше пів секунди в моєму коді, але займає близько 80 секунд, що, на вашу думку, повинно в основному блокувати на виході.
aschepler

А, я обійшов це, уникаючи printf.
aschepler

Відповіді:


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Потрібно тому , що readІНГ список з nодним зі своїх елементів main, в поєднанні з використанням nв take, змусить rна Intвсьому, що призводить до неприємних переткам з великими числами в питанні. Я міг би використати genericTake, але для цього потрібна import.

Цей код також має перевагу в тому, що майже тривіально розширюється на інші бази, ніж 10.

Введення зчитується з stdinдвох значень можна розділити будь-яким пробілом.


Ваш код повинен бути коротшим, якщо ви позбудетесь від задників
гордий haskeller

@proudhaskeller: не впевнений, оскільки навколо них немає дужок, щоб розділити оператор і операнд, не потребуючи пробілів.
TheSpanishInquisition

Я не можу читати Haskell, тому я не зовсім впевнений, що ти робиш. Чи вирішиться це r = 5; n = 65535протягом хвилини?
Мартін Ендер

@ MartinBüttner: Я чекав цього коментаря. Так, це, мабуть, буде, але не на моєму комп’ютері (чи хтось зараз, насправді). Проблема потребує більш досконалого алгоритму, я думаю. :(
TheSpanishInquisition

@TheSpanishInquisition Але ahould бути в змозі замінити y`mod`10з mod 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. Це займає занадто багато часу і підштовхує програму до обмеження хвилин на моєму робочому столі. Наразі деякі тестові випадки займають близько 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щоб описати звичайний процес запису числа у вигляді послідовності десяткових цифр. Його асортимент - це набір упорядкованих кортежів {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)як реальне число , отримане шляхом додавання нулів перед десятковими цифрами 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 != 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.

[Не закінчено ...]


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

Редагувати: Гаразд, це, мабуть, спосіб сповільнити виконання необхідної 1-хвилинної межі часу для 65К номерів.


1
Ви перевірили це на вимозі продуктивності?
Пітер Тейлор

2
У мене є сумніви, що це знайде 65 к таких цифр до того, як вибухне сонце.
Мартін Ендер

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 для мене це прекрасно працює. може бути, що він не відповідає вимогам щодо продуктивності, але я на комп’ютері, який я зараз є досить слабким ... Що ви зробили, щоб цей фрагмент коду працював?
Армін

1
Скопіював його в консоль і додав (5,4). Причина, що вона не буде працювати, полягає в тому, що їх кількість зростає дуже великою. а) Багато більше, ніж число у JS, може представляти точно та б) занадто велике, щоб було можливо повторити всі числа, щоб потрапити туди.
Мартін Ендер

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

1
Якщо unsigned long longце 64 біти, це недостатньо великий розмір.
Пітер Тейлор

Правда, я перейшов до рішення @ TheSpanishInquisition і використав замість цього python.
matsjoyce
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.