Зменшення дільника


21

Дільник числа n - це будь-яке число, яке рівномірно ділить n , включаючи 1 і n себе. Кількість дільників d (n) - скільки дільників має число. Ось d (n) для першої пари n:

n    divisors    d(n)
1    1           1
2    1, 2        2
3    1, 3        2
4    1, 2, 4     3
5    1, 5        2
6    1, 2, 3, 6  4

Ми можемо неодноразово віднімати кількість дільників від числа. Наприклад:

16                  = 16
16 - d(16) = 16 - 5 = 11
11 - d(11) = 11 - 2 = 9
 9 - d( 9) =  9 - 3 = 6
 6 - d( 6) =  6 - 4 = 2
 2 - d( 2) =  2 - 2 = 0

У цьому випадку було потрібно 5 кроків, щоб досягти 0.


Напишіть програму чи функцію, яка призначає негативне число n повертає кількість кроків, які потрібно зробити, щоб зменшити її до 0 шляхом повторного віднімання числа дільників.

Приклади:

0, 0
1, 1
6, 2
16, 5
100, 19
100000, 7534

5
Обов’язкове посилання OEIS: A155043
Sp3000

Відповіді:



6

Пітон, 49 байт

f=lambda n:n and-~f(sum(n%~x<0for x in range(n)))

orlp допоміг зберегти байт! І Sp3000 врятував ще двох. Спасибі!


1
Потрібно мати можливість скоротити речі, переміщаючи їх -~у n%-~kта видаляючи нижню межу діапазону.
orlp


4

Pyth, 10 байт

tl.ulf%NTS

Тестовий набір.

Пояснення

tl.ulf%NTS
tl.ulf%NTSNQ  implicit variables at the end
           Q  obtain the input number
  .u      N   repeat the following until result no longer unique:
         S        generate range from 1 to N
     f            filter for:
      %NT             T in that range, which N%T is truthy (not zero)
    l             length of that list
                  that means, we found the number of "non-divisors" of N
tl            number of iterations, minus 1.

3

Джулія, 31 байт

f(n)=n<1?0:f(sum(n%(1:n).>0))+1

Пряма рекурсивна реалізація.



2

JavaScript (ES6), 64 51 байт

f=n=>n&&[...Array(m=n)].map((_,i)=>m-=n%++i<1)|f(m)+1

Не питайте мене, чому я без зайвих зусиль використовував рекурсію хвоста.



1

05AB1E, 12 10 байт

Код:

[Ð>#Ñg-¼]¾

Пояснення:

[           # start infinite loop
 Ð          # triplicate current number
  >#        # increase by 1 and break if true
    Ñg      # get number of divisors
      -     # subtract number of divisors from number
       ¼    # increase counter
        ]   # end loop
         ¾  # print counter

Спробуйте в Інтернеті

Редагувати: збережено 2 байти та виправлено помилку із входом 0 завдяки @Adnan


Дуже хороша! Я намагався гольф це трохи, і отримав його до 10 байт: [Ð>#Ñg-¼]¾. Має бути спосіб її скоротити, хоча ...
Аднан

@LuisMendo Так, це D0Q#частина після збільшення лічильника. [Ð>#Ñg-¼]¾Код повинен працювати , 0хоча :).
Аднан

@Adnan: Я спробував версію, засновану на генеруванні всіх підрахунків до n і переході від індексу до значення за індексом і підрахунку, але не вдалося його скоротити таким чином.
Емінья


1

Mathcad, [tbd] байт

enter image description here


Схема еквівалентності байт Mathcad ще не визначена. Використовуючи грубу еквівалентність натискання клавіш, програма використовує близько 39 "байт". Зауважте, що в той час як оператори програмування виконують лише одну операцію клавіатури для введення (ctl-] і ctl-shft- # відповідно) - дійсно, їх можна вводити таким чином лише з клавіатури.

Що ви бачите, це саме те, що ставиться на робочий аркуш Mathcad. Mathcad оцінює рівняння / програми і виводить вихід на той самий аркуш (наприклад, після оператора оцінки '=' або на графіку).


1

MATL, 13 байт

tX`t:\ztt]Nq&

Спробуйте в Інтернеті

Пояснення:

t               % Duplicate input
 X`      ]      % while loop, consumes 1 input
   t:\z         % calculates n-d(n), by counting number non-divisors
       tt       % dupe twice, for while loop condition, next iteration and to keep in stack
          Nq&   % get stack size, decrement, display that value

1

Математика, 35 байт

If[#<1,0,#0[#-0~DivisorSigma~#]+1]&

Використання старого доброго DivisorSigma. @ MartinBüttner зазначає такі альтернативи:

If[#<1,0,#0[#-DivisorSum[#,1&]]+1]&
f@0=0;f@n_:=f[n-DivisorSum[n,1&]]+1

1

Хун , 93 76 байт

|=
r/@
?~
r
0
+($(r (sub r (lent (skim (gulf 1^r) |=(@ =(0 (mod r +<))))))))

Безголівки:

|=  r/@
?~  r
  0
=+  (skim (gulf 1^r) |=(@ =(0 (mod r +<))))
+($(r (sub r (lent -))))

Повертає функцію , яка приймає атом r. Створіть проміжне значення, яке містить усі девізори r(Складіть список [1..n], збережіть лише ті елементи, де (mod ri) ​​== 0). Якщо rдорівнює нулю зворотний нуль, інакше повертайте приріст значення повторюваних з r рівним r- (дільники довжини).

Код як-є займає нерозумно багато часу, щоб оцінити n = 100.000, цілком тому, що пошук девізорів для великих чисел складає гігантський список і відображає його. Пам'ять дільників отримує правильний вихід для n = 10 000, але я не заважав чекати 100 000


1

Haskell, 43 40 39 байт

g 0=0;g n=1+g(sum$min 1.mod n<$>[1..n])

Простий рекурсивний підхід. Приклад використання: g 16-> 5.

Редагувати: @Lynn зберегла 3 4 байти. Спасибі!


Як щодо g(sum$signum.mod n<$>[1..n])?
Лінн

Так, і min 1це на самому справі один байт коротше signum, навіть
Лінн

1

PowerShell v2 +, 74 67 байт

param($n)for($o=0;$n-gt0){$a=0;1..$n|%{$a+=!($n%$_)};$n-=$a;$o++}$o

Здається, досить тривалим порівняно з деякими іншими відповідями ...

Бере введення $n, вводить forцикл з умовою, що $nперевищує 0. Кожну ітерацію циклу ми встановлюємо помічником $a, а потім пробираємо через кожне число від 1до $n. Кожен внутрішній цикл ми перевіряємо на кожне число, щоб побачити, чи це дільник, і якщо так, то збільшуємо свого помічника $a(використовуючи булеве заперечення та неявну передачу на int). Потім віднімаємо, скільки дільників ми знайшли, $n-=$aі збільшуємо наш лічильник$o++ . Нарешті, ми виводимо $o.

Виконання займає багато часу, оскільки це важлива конструкція для циклу. Наприклад, біг n = 10,000на моїй машині (1 рік старого Core i5) займає майже 3 хвилини.


1

Ракетка - 126 байт До 98 байт 91 байт

Надзвичайно наївне рішення - можливо, можна було б скоротити багато пристойним алгоритмом та деякими хитрощами, які я не знаю

(define(g x[c 0][d 0][i 2])(cond[(= x 0)c][(= i x)(g d(+ 1 c))][(=(modulo x i)0)(g x c d(+ 1 i))][else(g x c(+ 1 d)(+ 1 i))]))

Редагувати: пояснення за запитом. Як я вже сказав, це надзвичайно наївне рекурсивне рішення і може бути набагато набагато коротшим.

(define (g x [c 0] [d 0] [i 2]) ;g is the name of the function - arguments are x (input), c (counter for steps), d (non-divisor counter), i (iterator)
  (cond
    [(= x 0) c] ;once x gets to 0 c is outputted
    [(= i x) (g d (+ 1 c))] ;if iterator reaches x then we recurse with d as input and add 1 to c
    [(= (modulo x i) 0) (g x c d (+ 1 i))] ;checks if iterator is non divisor, then adds it to d and increments iterator
    [else(g x c (+ 1 d) (+ 1 i))])) ;otherwise just increments iterator

Редагувати версію 2: 98 байт із менш німим алгоритмом (все ще досить тупий, хоча і може бути коротшим)

(define(g x)(if(< x 1)0(+ 1(g(length(filter(λ(y)(>(modulo x y)0))(cdr(build-list x values))))))))

Пояснення:

(define (g x) ;function name g, input x
  (if (< x 1)
      0 ;returns 0 if x < 1 (base case)
      (+ 1 ;simple recursion - adds 1 to output for each time we're looping
         (g (length ;the input we're passing is the length of... 
              (filter (λ (y) (> (modulo x y) 0)) ;the list where all numbers which are 0 modulo x are 0 are filtered out from...
                             (cdr (build-list x values)))))))) ;the list of all integers up to x, not including 0

Редагувати 3: Збережено 7 байт, замінивши (cdr(build-list x values))на(build-list x add1)

(define(g x)(if(< x 1)0(+ 1(g(length(filter(λ(y)(>(modulo x y)0))(build-list x add1)))))))

Привіт, і ласкаво просимо до PPCG! Чудовий пост! Чи можете ви пояснити своє рішення? (PS Я люблю Lisp!)
NoOneIsHere

@NoOneIsHere Відредаговано в
kronicmage

0

> <> , 52 + 2 = 54 байти

Номер введення повинен бути присутнім у стеку при запуску програми, тому для -vпрапора є +2 байти . Спробуйте в Інтернеті!

:0)?v~ln;>~$-]
03[}\::
@@:$<    v?=0:-1}+{~$?@@01%@:

4 дратівливих байта витрачаються на проблеми вирівнювання. Ба.

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

До речі, це працює в O(n^2)часі, тому я б не намагався n = 100000...


-vце один байт, а не два.
NoOneIsHere


0

Рубін, 42 байти

f=->n{n<1?0:1+f[n-(1..n).count{|i|n%i<1}]}

У найбільшому тестовому випадку є помилка переповнення стека 100000, ось ось ітеративна версія в межах 49 байт . Але, маючи на увазі O(N^2)складність, потрібен певний час .

->n{c=0;c+=1 while 0<n-=(1..n).count{|i|n%i<1};c}

0

Perl 5, 40 байт

sub f{@_?(1,f((1)x grep@_%$_,1..@_)):()}

Введення та вихід є списками необхідної кількості примірників 1.



0

Власне, 17 байт

";╗R`╜%`░l;"£╬klD

Спробуйте в Інтернеті! (Примітка: останній час випробування вийшов на TIO)

Пояснення:

";╗R`╜%`░l;"£╬klD
"          "£╬     while top of stack is truthy, call the function:
 ;╗                  push a copy of n to reg0
   R                 range(1,n+1) ([1,n])
    `  `░l             push the number of values where the following is truthy:
     ╜%                  k mod n
                       (this computes the number of non-divisors of n)
          ;            make a copy
              klD  push entire stack as list, count number of items, subtract 1
                   (the result is the number of times the function was called)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.