(KevinC's) Треугольная последовательность десятичных цифр


19

Входные данные:

Положительное целое число n, которое есть 1 <= n <= 25000.

Выход:

  1. В этой последовательности мы начинаем с десятичного числа 1 / n .
  2. Затем мы берем сумму цифр до n -й цифры после запятой (1-индексированная); с последующей суммой цифр до ( n -1) ', затем ( n -2)' и т. д. Продолжайте, пока n не станет 1.
  3. Выход - сумма всех этих вместе взятых.

Например:

n = 7
1/7 = 0.1428571428...
7th digit-sum = 1+4+2+8+5+7+1 = 28
6th digit-sum = 1+4+2+8+5+7 = 27
5th digit-sum = 1+4+2+8+5 = 20
4th digit-sum = 1+4+2+8 = 15
3rd digit-sum = 1+4+2 = 7
2nd digit-sum = 1+4 = 5
1st digit     = 1
Output = 28+27+20+15+7+5+1 = 103

Правила соревнований:

  • Если десятичная дробь 1 / n не имеет n цифр после запятой, пропущенные будут считаться 0 (т 1/2 = 0.50 => (5+0) + (5) = 10. Е. ).
  • Вы берете цифры без округления (то есть цифры 1/6, 166666а не 166667)

Основные правила:

  • К вашему ответу применяются стандартные правила , поэтому вы можете использовать STDIN / STDOUT, функции / метод с правильными параметрами, полные программы. Ваш звонок.
  • По умолчанию лазейки запрещены.
  • Если возможно, добавьте ссылку с тестом для вашего кода.
  • Также, пожалуйста, добавьте объяснение, если это необходимо.

Первые 1 - 50 в последовательности:

0, 10, 18, 23, 10, 96, 103, 52, 45, 10, 270, 253, 402, 403, 630, 183, 660, 765, 819, 95, 975, 1034, 1221, 1500, 96, 1479, 1197, 1658, 1953, 1305, 1674, 321, 816, 2490, 2704, 4235, 2022, 3242, 2295, 268, 2944, 3787, 3874, 4097, 1980, 4380, 4968, 3424, 4854, 98

Последние 24990 - 25000 в последовательности:

1405098782, 1417995426, 1364392256, 1404501980, 1408005544, 1377273489, 1395684561, 1405849947, 1406216741, 1142066735, 99984

8
Кто-то упомянул мое имя?
Кевин

Ответы:


6

Желе , 9 байт

R⁵*:%⁵+\S

Довольно медленно, но коротко. Попробуйте онлайн! или проверьте первые 50 тестовых случаев .

Как это устроено

R⁵*:%⁵+\S  Main link. Argument: n

R          Range; yield [1, ..., n].
 ⁵*        10 power; yield [10**1, ..., 10**n].
   :       Divide each power by n.
    %⁵     Take each quotient modulo 10.
           This yields all desired decimal digits.
      +\   Take the cumulative sum of the digits.
        S  Take the sum.

15

Mathematica, 42 байта

#&@@RealDigits[1/#,10,#,-1].(#-Range@#+1)&

или

#&@@RealDigits[1/#,10,#,-1].Range[#,1,-1]&

или

Tr@Accumulate@#&@@RealDigits[1/#,10,#,-1]&

объяснение

Возьмите пример из спецификации задачи. Мы хотим вычислить:

  1+4+2+8+5+7+1
+ 1+4+2+8+5+7
+ 1+4+2+8+5
+ 1+4+2+8
+ 1+4+2
+ 1+4
+ 1

Переставляя, это:

  1*7 + 4*6 + 2*5 + 8*4 + 5*3 + 7*2 + 1*1
= (1, 4, 2, 8, 5, 7, 1) . (7, 6, 5, 4, 3, 2, 1)

где .скалярное произведение двух векторов.

Это почти все решение.

#&@@RealDigits[1/#,10,#,-1]

Это дает нам первые Nдесятичные цифры 1/N( #&@@извлекает первый элемент RealDigitsрезультата, потому что это также возвращает смещение первой цифры, которое нас не волнует).

Затем мы получаем список Nсверху вниз, 1используя (#-Range@#+1)либо Range[#,1,-1], или , оба из которых короче Reverse@Range@#, и берём скалярное произведение.

Вместо этого альтернативное решение использует Accumulateдля вычисления списка всех сумм префиксов, а затем суммирует эти суммы префиксов с Tr.

Так как это действительно быстро даже для больших входных данных, ниже приведен график разброса последовательности до N = 100,000(выполнение всех из них и их построение заняло некоторое время):

введите описание изображения здесь
Нажмите для увеличения версии.

Синяя линия - наивная верхняя граница 9 N (N+1) / 2(если все десятичные цифры были 9), а оранжевая линия - ровно половина от этого. Неудивительно, что это прямо внутри основной ветви графика, поскольку статистически мы ожидаем, что средняя цифра будет 4,5.

Тонкая линия точек графика, которые вы видите под основной ветвью, - это дроби, которые заканчиваются ...3333..., поскольку все они расположены очень близко 3 N (N+1) / 2.


Очень хороший ответ, и я люблю график-сюжет! К сожалению, это не самое короткое время, и я не могу принять это как ответ. :) Если я не забуду, я мог бы получить небольшую награду за два дня за ответы намного больше, чем простое задание, которое я дал.
Кевин Круйссен

1
@KevinCruijssen Спасибо! :)
Мартин Эндер

6

05AB1E , 12 11 байт

Di<ë°¹÷.pSO

Попробуйте онлайн! или набор тестов для первых 50 номеров.

объяснение

              # implicit input n
Di<           # if n == 1 then 0
   ë          # else
    °¹÷       # 10^n // n
       .p     # get prefixes
         SO   # sum digits

Более эффективная версия для опробования больших чисел на TIO

Разница с более короткой версией заключается в том, что здесь мы суммируем произведение цифр и обращение их основанного на 1 индекса вместо суммирования цифр в префиксах.

Di<ë°¹÷SDgLR*O

Попробуйте онлайн!


5

Java 8, 181 169 166 153 142 байта

import java.math.*;n->{int m=n+2,r=0,i;for(;m>2;)for(i=m--;i-->2;r+=(BigDecimal.ONE.divide(new BigDecimal(n),n,3)+"").charAt(i)-48);return r;}

Объяснение:

Попробуй это здесь.

import java.math.*;   // Required import for BigDecimal

n->{                  // Method with integer as both parameter and return-type
  int m=n+2,          //  Copy of the input-integer plus 2
      r=0,            //  Result-integer, starting at 0
      i;              //  Index-integer
  for(;m>2;)          //  Loop (1) as long as `m` is larger than 2
    for(i=m--;        //   Set index `i` to `m`, and decrease `m` by one afterwards
        i-->2;        //   Inner loop (2) from `m` down to 2 (inclusive)
      r+=             //    Add to the result-sum:
         (BigDecimal.ONE.divide(
                      //     1 divided by,
           new BigDecimal(n),
                      //     the input
           n,3)       //     With the minimal required precision
          +"")        //     Convert this to a String
          .charAt(i)  //     Take the character of this String at index `i`
          -48         //     And convert it to a number
     );               //   End of inner loop (2)
                      //  End of loop (1) (implicit / single-line body)
  return r;           //  Return result
}                     // End of method

4

PHP, 66 65 байт

for($b=$c=$argv[$a=1];$c;)$o+=$c--*(($a=10*($a%$b))/$b^0);echo$o;

Адаптировано из этого ответа (также мной): Подразделение не очень маленьких чисел и предложенное им редактирование Йоргом Хюльсерманом. Используйте как:

php -r "for($b=$c=$argv[$a=1];$c;)$o+=$c--*(($a=10*($a%$b))/$b^0);echo$o;" 7

edit: исправил ошибку для +1 байта и сложил присвоение $ a в $ argv [1] для -2 байтов для чистого 1 байта меньше.


3

Scala, 84 байта

val b=BigDecimal
def?(& :Int)=1 to&map(x=>(""+b(1)/b(&))slice(2,x+2)map(_-48)sum)sum

Ungolfed:

def f(n: Int)={
  val digits = ""+BigDecimal(1)/BigDecimal(n)
  (1 to n).map( x=>
    digits.slice(2, x+2).map(d => d - 48).sum
  ).sum

Объяснение:

val b=BigDecimal   //define an alias for BigDecimal
def?(& :Int)=      //define a method called ? with an integer & as a parameter
  1 to &           //create a range from 1 to &
  map(x=>          //for each number x...
    (""+b(1)/b(&))   //calculate the fraction
    slice(2,x+2)     //and take the slice starting from the third element,
                     //(dropping the "1.") and containing x elements
    map(_-48)        //for each char, subtract 48 to get the integer value
    sum              //and sum them
  )sum             //and take the sum

Я мог бы сэкономить несколько байтов, используя способ, которым токенизируется компилятор: вызывая аргумент &, вы можете писать 1 to&mapвместо 1 to n map. То же правило относится к def?.


3

Желе , 11 байт

’aµR⁵*:µDFS

TryItOnline
Первые 50

Слишком медленно для больших тестовых случаев.

Как?

’aµR⁵*:µDFS - Main link: n
’           - decrement
 a          - and (to handle special case where n=1, to return 0 rather than 10)
  µ         - monadic chain separation
   R        - range: [1,2,...n]
    ⁵       - literal 10
     *      - exponentiation: [10,100,...,10^n]
      :     - integer division: [10//n,100//n,...,10^n//n]
       µ    - monadic chain separation
        D   - cast to a decimal list [[digits of 10//n],[digits of 100//n],...]
         F  - flatten into one list
          S - sum

2
Я не думаю, что я когда-либо видел ответ Желе, где объяснение является прямой линией ;-)
ETHproductions

Я почти поставил R⁵*эквивалент слева направо, но потом увидел красивую прямую линию :)
Джонатан Аллан

3

PHP, 76 байт

(Изменить -1 байт - Спасибо пользователю 59178 - ваше решение еще лучше)

for($c=substr(bcdiv(1,$a=$argv[1],$a),2);$i<$a;)$s+=($a-$i)*$c[$i++];echo$s;

Вы можете сохранить байт (точку с запятой), переместив $c=blahв первую частьfor(;;)
user59178

2

MATL, 19 байт

li/GEY$4LQ)!UYsG:)s

Попробуйте онлайн!

объяснение

l       % Push a 1 literal to the stack
i/      % Grab the input (n) and compute 1/n
GE      % Grab the input again and multiply by 2 (2n)
Y$      % Compute the first 2n digits of 1/n after the decimal
4LQ)    % Get only the digits past the decimal point
!U      % Convert to numbers
Ys      % Compute the cumulative sum
G:)     % Get the first n terms
s       % Sum the result and implicitly display

2

Groovy, 87 байт

Это было менее болезненно, чем я ожидал, и основано на моем ответе здесь :

{n->(1..n).collect{x->(1.0g.divide(n, n, 1)+"")[2..x+1].getChars().sum()-48*(x)}.sum()}

объяснение

1.0g - Используйте BigDecimal обозначения для одного.

.divide(n, n, 1)+"" - Разделить на n с точностью до n (только функция BigDecimal) и преобразовать в str.

(...)[2..x+1].getChars() - Получить подстроку текущей итерации в виде массива char.

.sum()-48*(x)- Суммируйте значения ASCII символов и уменьшите на 48 для каждого элемента. Это превращает значение из цифры ASCII в целое число, существенно экономя байты *.toInteger().

(1..n).collect{...}.sum() - Выполните эту функцию, перебирая каждую из цифр в делении, получая их все в одном массиве и суммируя.

Сохранено 2 байта и потерянная эффективность ...

Это более эффективная версия, которая не пересчитывает BigDecimal при каждой итерации.

{n->i=1.0g.divide(n, n, 1)+"";(1..n).collect{x->i[2..x+1].getChars().sum()-48*(x)}.sum()}

2

J, 27 байт

1#.[:+/\-{.10#.inv%<.@*10^]

использование

Входные данные являются расширенным целым числом.

   f =: 1#.[:+/\-{.10#.inv%<.@*10^]
   (,.f"0) (>: i. 50x) , 24990x + i. 11
    1          0
    2         10
    3         18
    4         23
    5         10
    6         96
    7        103
    8         52
    9         45
   10         10
   11        270
   12        253
   13        402
   14        403
   15        630
   16        183
   17        660
   18        765
   19        819
   20         95
   21        975
   22       1034
   23       1221
   24       1500
   25         96
   26       1479
   27       1197
   28       1658
   29       1953
   30       1305
   31       1674
   32        321
   33        816
   34       2490
   35       2704
   36       4235
   37       2022
   38       3242
   39       2295
   40        268
   41       2944
   42       3787
   43       3874
   44       4097
   45       1980
   46       4380
   47       4968
   48       3424
   49       4854
   50         98
24990 1405098782
24991 1417995426
24992 1364392256
24993 1404501980
24994 1408005544
24995 1377273489
24996 1395684561
24997 1405849947
24998 1406216741
24999 1142066735
25000      99984

Производительность хорошая, и для больших тестовых случаев требуется всего около 3 секунд.

   timex 'f 7x'
0.000119
   timex 'f 24999x'
3.8823
   timex 'f 25000x'
3.14903

объяснение

1#.[:+/\-{.10#.inv%<.@*10^]  Input: n
                          ]  Get n
                       10^   Raise 10 to the nth power
                  %          Get the reciprocal of n
                      *      Multiply (1/n) with (10^n)
                   <.@       Floor it
           10#.inv           Convert it to a list of base 10 digits
        -                    Negate n
         {.                  Take the last n values from the list of digits
                             (This is to handle the case for n = 1)
   [:  \                     For each prefix of the list of digits
     +/                        Reduce it using addition to get the sum
1#.                          Convert those sums as base 1 digits and return
                             (This is equivalent to taking the sum)

2

Желе , 10 байт

⁵*:⁸D+\_ỊS

Не самый короткий подход , но довольно эффективный. Попробуйте онлайн! или проверьте все тесты .

Как это устроено

⁵*:⁸D+\_ỊS  Main link. Argument: n (integer)

⁵*          Yield 10**n.
  :⁸        Divide 10**n by n (integer division).
    D       Convert the quotient to base 10.
     +\     Take the cumulative sum of the digits.
        Ị   Insignificant; yield (abs(n) <= 1).
       _    Subtract the resulting Boolean from each decimal digit.
            This takes care of edge case n = 1, which would return 2 otherwise.
         S  Take the sum.

1

Python 2, 90 байт

lambda o:sum([sum([int(i)for i in s])for s in map(lambda x:str(1.0/o)[2:x],range(3,3+o))])

Не красиво, но сделано через деление с плавающей точкой, затем преобразование в строку и затем итеративный выбор индекса строки, чтобы получить треугольник чисел, затем выполнить понимание списка и преобразовать каждый символ в целое и, наконец, суммировать их все.


1

JavaScript (ES6), 47 байт

f=(b,a=1%b,c=b+1)=>c&&(a/b|0)*c+f(b,a%b*10,c-1)

Как это устроено

Этот ответ демонстрирует методику вычисления c десятичных цифр a / b :

f=(a,b,c,d=".")=>~c?(a/b|0)+d+f(a%b*10,b,c-1,""):d

Это станет отличной отправной точкой для этого испытания. Сначала мы можем немного изменить его, чтобы он вычислял b десятичных цифр 1 / b , переупорядочивая параметры и устанавливая значения по умолчанию:

f=(b,a=1,c=b,d=".")=>~c?(a/b|0)+d+f(b,a%b*10,c-1,""):d

Затем мы можем изменить это так, чтобы он вычислял сумму первых b десятичных цифр, а не объединял их (это устраняет dпараметр):

f=(b,a=1,c=b)=>~c?(a/b|0)+f(b,a%b*10,c-1):0

Мы почти на пути к решению; теперь нам нужно просто умножить каждую цифру на c + 1 :

f=(b,a=1,c=b)=>~c?(a/b|0)*-~c+f(b,a%b*10,c-1):0

Хм, это кажется немного длинным. Что если мы увеличим c на 1 для начала?

f=(b,a=1,c=b+1)=>c?(a/b|0)*c+f(b,a%b*10,c-1):0

Это экономит один байт. И вот способ сохранить еще один:

f=(b,a=1,c=b+1)=>c&&(a/b|0)*c+f(b,a%b*10,c-1)

И теперь у нас есть наш ответ. f(7)это 103, f(11)это 270, f(1)это ... 2? О, мы забыли учесть случай, когда a / b равен 1 на первой итерации (т.е. b равно 1). Давайте сделаем что-нибудь с этим:

f=(b,a=1%b,c=b+1)=>c&&(a/b|0)*c+f(b,a%b*10,c-1)

1 mod b всегда равно 1 , если только b не равно 1 , в этом случае это будет 0 . Наша программа теперь корректна для всех входных данных, на 47 байтов .



0

C, 53 байта

f(n,i,x,s){while(i)x=10*(x%n),s+=i--*(x/n);return s;}

Ниже основной для сделать некоторый тест ...

//44,79
#define R return
#define F for
#define U unsigned
#define N int
#define B break
#define I if
#define L(i) for(;i-->0;)
#define J(a,b)  if(a)goto b
#define G goto
#define P printf
#define D double
#define C unsigned char
#define A getchar()
#define O putchar
#define M main
#define Y malloc
#define Z free
#define S sizeof
#define T struct
#define E else
#define Q static
#define X continue  
main()
{N  k, a=0, b=0, i;

 F(i=1;i<50;++i) 
       P("f(%u)=%u |", i, f(i,i,1,0));
 P("\n");
 F(i=24990;i<=25000;++i) 
       P("f(%u)=%u |", i, f(i,i,1,0));
 P("\n");
 R 0;
}

/*
f(1)=0 |f(2)=10 |f(3)=18 |f(4)=23 |f(5)=10 |f(6)=96 |f(7)=103 |f(8)=52 |f(9)=45
f(10)=10 |f(11)=270 |f(12)=253 |f(13)=402 |f(14)=403 |f(15)=630 |f(16)=183 |f(17)=660 
f(18)=765 |f(19)=819 |f(20)=95 |f(21)=975 |f(22)=1034 |f(23)=1221 |f(24)=1500
f(25)=96 |f(26)=1479 |f(27)=1197 |f(28)=1658 |f(29)=1953 |f(30)=1305 |f(31)=1674
f(32)=321 |f(33)=816 |f(34)=2490 |f(35)=2704 |f(36)=4235 |f(37)=2022 |f(38)=3242
f(39)=2295 |f(40)=268 |f(41)=2944 |f(42)=3787 |f(43)=3874 |f(44)=4097 |f(45)=1980
f(46)=4380 |f(47)=4968 |f(48)=3424 |f(49)=4854 |
f(24990)=1405098782 |f(24991)=1417995426 |f(24992)=1364392256 |f(24993)=1404501980
f(24994)=1408005544 |f(24995)=1377273489 |f(24996)=1395684561 |f(24997)=1405849947 
f(24998)=1406216741 |f(24999)=1142066735 |f(25000)=99984 
*/

Почему кто-то проголосовал за это? это потому что какая-то ошибка? это потому, что я не нахожу подходящих минут для него или нее? Для меня этого количества символов достаточно и хорошо, не стесняйтесь ответить на этот ответ, как и на другой, где я не могу говорить
RosLuP

3
Как другие прокомментировали другие ваши ответы, смысл кода гольф состоит в том, чтобы сделать код как можно более коротким , но вы по-прежнему включаете кучу макросов без веской причины. f(n,i,x,s){while(i)x=10*(x%n),s+=i--*(x/n);return s;}длиной всего 53 байта.
Деннис
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.