Остання ненульова цифра n!


22

Враховуючи ціле число 1 ≤ N ≤ 1,000,000 як вихід, виведіть останню ненульову цифру N! , де ! є факторіальним (добуток усіх чисел від 1 до N включно). Це послідовність OEIS A008904 .

Програму потрібно закінчити протягом 10 секунд на розумній машині для будь-якого дійсного введення.

Випробування

1 => 1
2 => 2
3 => 6
4 => 4
5 => 2
6 => 2
7 => 4
8 => 2
9 => 8
10 => 8
100 => 4
1000 => 2
10000 => 8
100000 => 6
1000000 => 4

Це тому найкоротший код у байтах виграє!


Єдина функція або повна програма?
Joey

@joey Ні, це просто тестові випадки. Один вхід, Один вихід.
fR0DDY

@joey Повна програма.
fR0DDY

1
Вимога до повноцінної програми відмовляється ...
Ерік Переможник

2
@EriktheOutgolfer це від ~ 7 років тому, тому я не думаю, що це було визначено в той час
NoOneIsHere

Відповіді:


8

Рубін - 63 ч

f=->n{n<2?1:6*[1,1,2,6,4,4,4,8,4,6][n%10]*3**(n/5%4)*f[n/5]%10}

Джерело - http://oeis.org/A008904

Обробляє f до тисячі цифр за секунду.

Тест

irb(main):014:0> for n in 2..6
irb(main):015:1> puts f[10**n]
irb(main):016:1> end
4
2
8
6
4

11

Математика, 45 36 байт

Last@Select[IntegerDigits[#!],#>0&]&

Дуже легко читати для виграшної відповіді. :) (Знову ж таки, ще немає подання GolfScript & Co..)

Це обробляє введення 1000000 приблизно за 5 секунд на моїй машині.


1
Математика - це майже ідеальна мова для цього питання.
Майкл Стерн


3

PARI / GP - 27 байт

Це торгує швидкістю для розміру - тестова шафа займає тривалий час (~ 6 секунд).

n->n!/10^valuation(n!,5)%10

Ця версія набагато швидша (~ 15 мікросекунд), але займає 81 байт:

n->r=1;while(n,r*=Mod(4,10)^(n\10%2)*[1,2,6,4,2,2,4,2,8][max(n%10,1)];n\=5);lift(r)

Ви можете скористатися цим (не гольф) кодом для тестування:

[%(10^n) | n <- [1..6]]

2

Windows PowerShell, 53 56 59 60 63 73 90

($a=1).."$input"|%{$a="$($a*$_)".trim('0')%1e7}
$a%10

Примітки:

  • Триває більше хвилини на число, близьке до 100 000. Однак для видалення нулів в кінці потрібне перетворення в рядок, для обчислень потрібне число, тому перетворення неминучі в будь-якому випадку.

Історія:

  • 2011-02-08 10:31 (90) - Перша спроба.
  • 2011-02-08 10:33 (73) - Модуль коротший, ніж нарізання та з'єднання.
  • 2011-02-08 10:34 (63) - Непотрібна обробка.
  • 2011-02-08 10:37 (60) - Непотрібна передача числа. Модуль вже робить це чудово.
  • 2011-02-08 10:40 (59) - Деякі вкладки.
  • 2011-02-08 11:00 (56) - Що я говорив раніше про скорочення модуля? Застосовується і до результатів.
  • 2011-02-08 11:01 (53) - Кастинг $inputна рядок достатній; кастинг до intзастосовується неявно.

2

Перл, 53 58 61 символів

Всі пробіли можна видалити, але я залишив це для "читабельності". Примітка: не використовувати якусь дурно виражену формулу від Sloane.

sub f {
    $_ = $1 * ++$n || 1, /(.{1,7}?)0*$/ while $n < $_[0];
    $1 % 10
}

Обчислює f (10 ^ 6) за 8,7 секунди на моїй машині.

Оновлення : ОП хотів, щоб це була ціла програма:

$_ = $1 * ++$n || 1, /(.{1,7}?)0*$/ while $n < $ARGV[0];
print $1 % 10

Це складає 55 символів.


2

CJam - 28

1ri{I)*_AbW%{}#A\#/1e7%}fIA%

Ви можете спробувати його на веб-сайті http://cjam.aditsu.net/ для значень до 10000 або близько того; для більшої кількості слід використовувати інтерпретатор Java . 1000000 працює на моєму ноутбуці приблизно за 3 секунди.

Пояснення:

На жаль, пряме рішення занадто повільне, тому я зберігаю лише останні 7 цифр (перед кінцевими нулями) після кожного множення.

1           push 1 on the stack
ri          read a token and convert to integer
{           loop (for I from 0 to N - 1)
    I)      push I and increment
    *       multiply with the previous value (initially 1)
    _Ab     duplicate and convert to array of digits
    W%      reverse array
    {}#     find the position of the first non-zero digit
    A\#     raise 10 to that power
    /       divide, thus removing all trailing zeros
    1e7%    keep the remainder modulo 10000000
}fI         end for loop
A%          get the last digit

Примітка: ця мова набагато новіша, ніж питання.



2

05AB1E , 4 байти

!0м¤

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

Пояснення

!0    # Push the factorial of the input and 0
  м   # Remove the occurences of 0 in the factorial
   ¤  # Push the last element, implicit display

1
Версія TIO вичерпана (60-ті роки) на останньому тестовому випадку - як ви її отримали протягом 10 секунд на "розумній машині"?
Toby Speight

2

Желе , 4 байти

!Ṛȯ/

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

Пояснення

Використовує той факт, що коли (зворотний список; не векторизується) застосовується до цілого числа, воно автоматично приймає D(цифри) спочатку.

З введенням 8:

!Ṛȯ/
!     Factorial: 8! = 40320
 Ṛ    Reverse: [0,2,3,0,4]
   /  Reduce by...
  ȯ   ...logical OR: ((((0ȯ2)ȯ3)ȯ0)ȯ4) = first truthy element = 2

Я не думаю, що існує один байт "першого елемента" (який ȯ/діє), але якщо є, то це може бути скорочено до трьох байтів.


2

Java (OpenJDK 8) , 62 байти

n->{long f=n;for(;n>1||f%10==0;)f=n>1?f*--n:f/10;return f%10;}

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

Подібно до @Kevin Cruijssen, але економить 5 байт, поєднуючи петлі.


Ласкаво просимо до PPCG! Гарний перший пост! Сподіваюсь, ви тримаєтесь!
Rɪᴋᴇʀ

Ласкаво просимо до PPCG! Я згоден з @Riker, чудовий перший пост. Молодці гольф мій код, комбінуючи петлі. Ви можете пограти ще на 1 байт у своїй поточній відповіді, замінивши ||на |, а додатковий байт - замінивши ==0на <1. Насолодитися перебуванням!
Kevin Cruijssen

2

C, 150 140 135 байт

r,d;f(k,x){r=x<5?3:f(k+1,x/5);return(d=x%5)?r*"33436"[d]*(1<<d*k%4)%5:r;}main(int c,char**v){c=atoi(*++v);printf("%d",c<2?1:2*f(0,c));}

Це версія для систем ASCII; замінити рядок 33436з 11214для EBCDIC системи, або \1\1\2\1\4для портативної програми.

Рішення C трохи заважають вимозі забезпечити повну програму; однак це повністю відповідає на питання.

Спробуйте в Інтернеті (вимагає Javascript):

Пояснення

Він заснований на алгоритмі, викладеному в Найменш значущому не нульовому розряді n"! , обернувшись так, що ми повторимо пошук найвищої потужності з п'яти, і зробимо розрахунок на виході. Таблиці констант були занадто великими, тому я зменшив їх, знайшовши залежність між попереднім залишком r, поточною цифрою dта глибиною рекурсії k:

     0    1       2       3    4  =d
  0  0  3×2^k  1×2^2k  3×2^3k  2
  1  1  1×2^k  2×2^2k  1×2^3k  4
r 2  2  2×2^k  4×2^2k  2×2^3k  3
  3  3  3×2^k  3×2^2k  3×2^3k  2
  4  4  4×2^k  4×2^2k  4×2^3k  1

Бо r>0це вирішується на постійний часr часи 2^dk(мод 5); постійні знаходяться a[]внизу (позначено кодом для гольфу). Ми також спостерігаємо, що (2^4)%5це 1, тому ми можемо зменшити показник, щоб уникнути переповнення діапазону int.

const int a[] = { 1, 1, 2, 1, 4 };
int f(int k, int x){
    int r = x<5 ? 3 : f(k+1,x/5); /* residue - from recursing to higher-order quinary digits */
    int d = x%5;
    if (!d)
        return r;
    return r * a[d] * (1<<d*k%4) % 5;
}

int main(int c, char **v)
{
    c = atoi(*++v);
    printf("%d",
           c<2
           ? 1                  /* special-case 0 & 1 */
           : 2*f(0,c));         /* otherwise, it's 2 times r */
}

Тести:

$ for i in 100 1000 10000 100000; do echo $i: `./694 $i`; done
100: 4
1000: 2
10000: 8
100000: 6
1000000: 4

Продуктивність також поважна. Ось максимальний вхід для 32-розрядної системи int:

$ time ./694 2147483647
8
real    0m0.001s
user    0m0.000s
sys     0m0.000s

У мене були ті ж таймінги з максимальним 64-бітним int .


1
Можливо, буде цікаво відзначити, що 2147483647!має понад 19 мільярдів цифр і (2^63-1)!понад 170 000 000 000 000 000 000 цифр, тож це велика перемога в обчисленні факторіалів. 1000000!як зазначено в питанні, можливо розрахувати на поточному обладнання; це лише 5½ мільйонів цифр. :-)
Toby Speight

1

PHP - 105

 <?foreach(explode("\n",`cat`)as$n)if($n){$f=rtrim(gmp_strval(gmp_fact($n)),'0');echo substr($f,-1)."\n";}

Працює менше 10 секунд із заданою тестовою шкалою.


1

Python3

239 символів

Можу зробити 10000 за ~ 3,2 секунди (Ideone скорочує мене за 8 секунд, я впевнений, що це займе більше 10 секунд, хоча :()

from functools import *
N=100
r=range
s=(p for p in r(2,N)if all(p%n>0for n in r(2,p)))
f=lambda n,x:n//x+(n//x>0and f(n//x,x)or 0)
e=list([p,f(N,p)]for p in s)
e[0][1]-=e[2][1]
e[2][1]=0
print(reduce(lambda x,y:x*y,map(lambda x:x[0]**x[1],e))%10)

Python2.6

299 символів (трохи швидше)

from itertools import *
N=100000
r=xrange
def s(c=count(2)):
        while 1:p=c.next();c=ifilter(p.__rmod__,c);yield p
f=lambda n,x:n//x+(n//x>0and f(n//x,x)or 0)
e=[[p,f(N,p)]for p in takewhile(lambda x:x<N,s())]
e[0][1]-=e[2][1]
e[2][1]=0
print(reduce(lambda x,y:x*y,map(lambda x:pow(x[0],x[1],10),e))%10)

1

Haskell, 78 символів

f n=head$dropWhile(=='0')$reverse$show$product[1..n]
main=interact(show.f.read)

(Ймовірно, потрібно буде скласти, щоб обчислити 1 000 000! За 10 секунд).


Збережіть два знаки , замініть його foldl1на product(cf codegolf.stackexchange.com/questions/607/find-the-factorial/… ). Але ви насправді спробували з 1000000! ?
JB

PS: не повна програма.
JB

Вибачте, робив це до того, як було з’ясовано в коментарях. Я його оновлю.
стусміт

1

J - 42 40 символів

Ціла програма. Збережіть цю програму у файлі та запустіть jconsole script.ijs 1234. Зауважте, що ця програма не виходить з інтерпретатора після друку результату. Введіть ^Dабо exit]0для виходу з перекладача.

echo([:{:@(#~*)10&#.inv@*)/1+i.".>{:ARGV

Ось пояснення:

  • x #. yінтерпретує цілий вектор yяк базове xчисло; наприклад, 10 #. 1 2 3 4урожайність 1234.
  • u invдає зворотній бік дієслова u. Зокрема, x #. inv yпредставляє yв якості базового xчисла; наприклад, 10 #. 1234урожайність 1 2 3 4. Зауважте, що invвизначено як ^:_1, тобто uзастосовано -1 раз.
  • x * yце продукт з xі y, таким чином , x 10&#.inv@* yдає уявлення основою 10 з продукту xіy .
  • x # yкопіює n -й елемент так yсамо часто, як n -й елемент x; коли xвектор булевих, xвибирає, які предмети yбрати. Наприклад, 1 0 1 0 # 1 2 3 4урожайність 1 3.
  • * yдає Signum з y.
  • x u~ yє рефлексивний з u, тобто такий же , як y u x.
  • Таким чином, y #~ * yвиходить вектор всіх yпозитивних позицій. У мовчазних позначеннях це може бути написано гачком як (#~ *).
  • {: yдає останній пункт у y.
  • зібравшись разом, ми отримуємо негласну фразу ([:{:@(#~*)10&#.inv@*).
  • u/ yце скорочення від y, тобто, довічного дієслово uвставляється між елементами y. Наприклад, +/1 2 3 4це як 1 + 2 + 3 + 4і врожайність10 .
  • Таким чином, словосполучення ([:{:@(#~*)10&#.inv@*)/ yдає останню цифру добутку предметів y.
  • ARGV - це віконний вектор аргументів командного рядка.
  • ".>{:ARGV є останнім аргументом без коробки та інтерпретується як число.
  • i. yобчислює натуральні числа від 0до y - 1.
  • Таким чином, 1+i. yвиходить натуральне число від 1до y. Я міг би також використати >: приріст тут, але 1+чіткіше при тій же вартості символів.
  • Вся програма просто застосовується 1+i.".>{:ARGV(вектор 1до числа в останньому аргументі командного рядка) до дієслова ([:{:@(#~*)10&#.inv@*)/і друкує результат за допомогою echo.


1

R , 63 55 51 46 байт

Обчислює факториал, витягує останню ненульову цифру. Завдяки Джузеппе за надання базової структури.

(y=(gamma(scan()+1))%/%10^(0:1e5)%%10)[!!y][1]

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

Як варіант, моя стара 51-байтна відповідь:

Обчислює факториал, перетворює на символи, видаляє всі 0s, а потім приймає остаточний символ. Збережено 2 байти завдяки Джузеппе.

substring(x<-gsub("0","",gamma(scan())+1),nchar(x))

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


1
gamma(x+1)коротше, ніжfactorial(x)
Джузеппе

без перетворення рядків, найкраще мені вдалося отримати (y=(x<-gamma(scan()+1))%/%10^(0:nchar(x))%%10)[!!y][1]54 байти.
Джузеппе

@Giuseppe Ми можемо замінити nchar(x)з 1e5для розчину 46 байт! Приємно йти.
rturnbull



1

C (gcc) , 72 байти (функція)

f(n,d)long long n,d;{for(d=1;n;d%=10000)for(d*=n--;d%10<1;d/=10);d%=10;}

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

C (gcc) , 101 99 байт (вся програма)

main(){long long n,d=1;for(scanf("%lld",&n);n;d%=10000)for(d*=n--;d%10<1;d/=10);printf("%d",d%10);}

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

Це питання просто сором'язливий 8 років, тому "розумна машина" не є такою ж, як тоді, але я на моєму комп’ютері отримую періоди ~ 0,01 секунди, коли разом роблю всі тестові справи, тому, якщо комп'ютери не зростають у швидкості з коефіцієнтом 1000 в останнє десятиліття, це повинно бути добре.


Закон Мура до сих пір тримається, тому воно повинно бути приблизно в 16 разів швидше
лише ASCII

Також функція чудова
лише для ASCII,


0

Attache , 26 байт

Last@`\&:(All@V)@Digits@`!

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

Пояснення

Last@`\&:(All@V)@Digits@`!

Це склад з 4 функцій:

  • `! - це функціональна версія факторного оператора
  • Digits - це отримує цифри факторіалу
  • \&:(All@V)- Це функція відбору. Він працює шляхом лівого з'єднання ( &:) функції All@Vдо \, що вибрати. У свою чергу, All@Vце короткий спосіб тестування, якщо число не дорівнює 0. Це працює, передаючи свій вхід у вектор0 -> [0] , передаючи а потім запитує, чи всі ці члени є неправдивими (тобто не 0). Це дає цифри числа без 0.
  • Last - це просто отримує останній член цього масиву.

Це здається неймовірно повільним - час TIO вичерпано (1 хвилина) на тестовому випадку 100000 - як ви отримали результат 1000000 протягом 10 секунд?
Toby Speight

@TobySpeight Коли я відповів на це завдання, то конкретної вимоги там не було (перевірте історію редагування).
Conor O'Brien

Ах, я мав би подивитися на історію! Ви все ж перевірили всі тести у запитанні?
Toby Speight

Здається, в цей період було невдало відповідей, коли строк було знято з питання - це дуже прикро.
Toby Speight

@TobySpeight Так, я. Це прикро, і я не впевнений у політиці щодо цього.
Conor O'Brien

0

APL (Dyalog Unicode) , 18 15 байт

{⊢/⍵/⍨0≠⍎¨⍵}⍕∘!

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

Мовчазна префіксальна функція. Повертає правильну цифру для одного тестового випадку або рядок цифр для декількох тестових випадків.

Завдяки @ Adám та @ErikTheOutgolfer по 3 байти кожен.

Як?

{⊢/⍵/⍨0≠⍎¨⍵}⍕∘!  Main function. Argument is a number following the !.
              !  Factorial
                then
                Format (stringify)
        ⍎¨⍵}     Execute (turn to number) each digit of the argument
      0         Check if each is 0. This returns a boolean vector
                Swap arguments for the following fn/op
   ⍵/            Replicate. This takes a boolean vector as left arg and returns the truthy elements of the right arg. E.g.: 1 1 0/1 2 3  1 2.
{⊢/              Reduce. This returns the rightmost (last) element of a vector argument.

0

APL NARS, 28 байт, 14 символів

{↑≠v/v←⌽⍎¨⍕!⍵}

Я не знаю чому, але це пройти тест:

  q←{↑≠v/v←⌽⍎¨⍕!⍵}       
  q¨1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 6 4 2 2 4 2 8 8 8 6 8 2 

0

AWK , 47 57 байт

{for(p=$1;--$1;p=(p*$1)%1e4)while(!(p%10))p/=10;$0=p%10}1

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

Оригінальне рішення не дуже добре впоралося з "великими" вхідними значеннями. Може додати, -Mщоб змусити його працювати, але це також вимагає значно більше часу на обробку.


Так, @TobySpeight, infне %дуже добре. :(
Роберт Бенсон

Ага ... переглядаючи версію запитання, на яке я відповів, велика кількість не потрібна.
Роберт Бенсон

-2

Japt , 6 байт

Придумав декілька різних 6-байтних, але мені це найбільше сподобалось. Я переконаний, що повинен бути спосіб зробити це через 5.

Êsw ìv

Спробуй це


Пояснення

Êобчислює факторіал введення, sперетворює його в рядок і назад до цілого числа після того, як wйого перевернув, ìперетворює результат у масив цифр і vповертає перший елемент.


Альтернативи

Êì w æ
ÊìÈf Ì
Êì f o
Êsw sg
Êìf ìo
Êìf ìÌ

Скільки часу потрібно для виконання всіх тестових випадків?
Toby Speight

@TobySpeight; це дуже легко перевірити, перейшовши за посиланням, щоб спробувати його. Зауважте, що останні 4 тестових випадки не вдасться, оскільки їхні фактичні факти перевищують максимальне ціле число JavaScript.
Кудлатий

Тож це насправді не вирішує проблему? У запитанні сказано, що він повинен досягти успіху для 1 ≤ N ≤ 1,000,000 . Інші відповіді демонструють, що для обчислення відповіді вам не потрібно мати можливість зберігати фактор.
Toby Speight

Я спробував онлайн-тест, але час вийшов на перший тестовий випадок, який я спробував (1000).
Toby Speight

-2

Perl 5 , 36 + 10 ( -p -Mbigint) = 46 байт

$"=$_;$_*=$"while$"-=1;($_)=/(.)0*$/

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


Версія TIO не відповідає першим двом випробуваним тестам: 1000000 ⇒ f (має бути 4 ) і 100 ⇒ 7(має бути 4 )
Toby Speight

Він переповнює розмір int. Нова версія працює за допомогою bigint. Продуктивність як і раніше залишає бажати кращого, оскільки це груба сила розрахунку. Це означає, що він збільшується на TIO для більшої кількості.
Xcali
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.