Сума двійкових підрядів


16

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

Input:
  11
Binary:
  11 -> 1011
Substrings:
  101 = 5
  011 = 3
  10  = 2
  01  = 1
  11  = 3
  1   = 1
  0   = 0
  1   = 1
  1   = 1
Sum:
  5+3+2+1+3+1+0+1+1=17
Output:
  17

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

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

Тестові приклади:

2  => 1
3  => 2
4  => 3
5  => 5
6  => 7
7  => 9
8  => 7
9  => 10
10 => 14
11 => 17

4
Цікаво, що виключення повнорозмірного підрядка є суттєвим додатковим викликом.
Пітер Тейлор

Відповіді:


12

Желе, 10 7 байт

BṡRḄFS_

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

Як це працює

BṡRḄFS_  Main link. Input: n

B        Convert n to base 2.
  R      Yield [1, ..., n].
 ṡ       Get all overlapping slices of lengths 1 to n.
         This yields empty arrays if the slice size is longer than the binary list.
   Ḅ     Convert each binary list to integer.
    F    Flatten the resulting, nested list.
     S   Compute the sum of the result.
      _  Subtract n from the sum.

Яке кодування дає вам 1 байт / char для цієї програми?
Toby Speight

1
@TobySpeight Jelly використовує власну кодову сторінку.
спагето



5

Python 3, 111 символів

N=bin(int(input()))[2:];L=len(N);r=range;print(sum(int(n,2)for n in[N[j:j+i]for i in r(1,L)for j in r(L-i+1)]))

EDIT : Пояснення:

N=bin(int(input()))[2:]

Перетворіть вхідний рядок у int, потім int у двійковий рядок та видаліть його перші два символи, оскільки the bin метод повертає рядок у форматі0b...

Візьміть усі підрядки двійкового рядка, перетворіть їх у десяткові за допомогою int(n, 2)і підсумуйте.

[N[j:j+i]for i in r(1,L)for j in r(L-i+1)]

- це список усіх підрядків. Негольована версія:

def all_substrings(N):
    result = []
    for i in range(1, len(N)):
        for j in range(len(N) - i + 1):
            result.append(N[j:j+i])
    return result

Сподіваюсь, це допомагає.


4

CJam (22 байти)

Це на один байт довше, ніж поточна найкраща відповідь CJam, але, ймовірно, цей підхід може бути прибутково адаптований до деяких інших мов.

3,ri_2b_,,:).*\+fbW%:-

Демонстрація в Інтернеті

Аналіз

Припустимо, що питання було

обчислити суму підрядів двійкового числа

без шматочка

довжина якої коротша від початкового числа

Тоді не надто важко показати, що найзначніший біт відбувається із загальною вагою, 1*(2^B-1)де Bкількість біт; другий за значимістю біт відбувається із загальною вагою 2*(2^(B-1)-1); аж до найбільшого значущого біта, який відбувається при загальній вазі B*(2^1-1).

Враховуючи тепер віднімання вихідного числа x, ми закінчуємо суму

sum_i (x & 2^i) * 2^i * 2*(B-i)  -  sum_i (x & 2^i) * (B-i)  -  x

Розсічення

3,        e# Put [0 1 2] on the stack - we'll need it later
ri_       e# Get the input x and copy it
2b        e# Convert the copy to base 2
_,,:).*   e# Pointwise multiply by 1 plus the index
\+        e# Append x to the resulting array, giving A
fb        e# Map a base conversion
W%:-      e# Reverse and fold a subtraction

Перерахунок на базу 2 дає першу частину основної суми плюс x; до основи 1 надається друга частина плюс x; а до бази 0 дається просто x, тому віднімання бази-1 від бази-2 xвідміни s, а віднімання бази-0 дає бажаний результат.


3

JavaScript (ES6), 78 байт

n=>[...n.toString(2)].map(c=>[...s+=c].map((_,i)=>n-='0b'+s.slice(i)),s='')|-n

Зовнішній mapстворює провідні підрядки nбінарного представлення; внутрішня частина витягує кінцеві підрядки провідних підрядів, таким чином охоплюючи всі можливі підрядки, включаючи оригінальне двійкове подання.

Кожна підрядка перетворюється з двійкової назад у десяткову та віднімається від вихідного вводу, оскільки це трохи коротше, ніж їх додавання та віднімання вихідного вводу.


2

Математика, 73 70 байт

Tr[FromDigits[#,2]&/@StringCases[#~IntegerString~2,__,Overlaps->All]]&

Функція. Integer-> Integer


1
Шкода, що математика не має чудових інструментів для роботи зі списками.
Сіммонс

1

Сітківка , 64

.*
$*
+`(1+)\1
$1a
a1
1
r&!M`.*
&!M`.*
^.*

+`1(a*)\b
a$.1$*1;
;

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

Поетапний опис на високому рівні: конвертуйте десятковий в одинарний, унарний у двійковий, отримуйте префікси, отримуйте суфікси префіксів, скидайте початкове число, перетворюйте двійкові в одинарні, повертайте кількість. Я напишу більш детальний опис, як тільки я закінчу гольф, багато з цих етапів здаються підозрілими ...


1

C, 71 байт

f(n){int a=0,m=0,i;for(;++m<n;m+=m)for(i=n;i+i>m;i/=2)a+=i&m;return a;}

Ми підтримуємо акумулятор aі маску m. Маска починається з 1 і стає щоразу на один біт довше зовнішньої петлі. У внутрішньому циклі копія iвводу послідовно зміщується праворуч, поки вона не стане коротшою за маску, накопичуючи значення маскування кожного разу.

Тестова програма

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
    while (*++argv) {
        int n = atoi(*argv);
        printf("%d -> %d\n", n, f(n));
    }
    return 0;
}

Тестовий вихід

./73793 $(seq 0 11)
0 -> 0
1 -> 0
2 -> 1
3 -> 2
4 -> 3
5 -> 5
6 -> 7
7 -> 9
8 -> 7
9 -> 10
10 -> 14
11 -> 17

1

C #, 148 байт

int x(int i){int s,r=0,j=i,p=System.Convert.ToString(i,2).Length+1,k;for(;--p>-1;){k=j;s=-1;for(;++s<p;)r+=(k>>=1);j=(i&((1<<p-1)-1))<<1;}return r;}

Або якщо я додам імпорт "за допомогою статичного System.Math;" то 138 с

int x(int i){int s,r=0,j=i,p=(int)Round(Log(i,2)+1.49,0),k;for(;--p>-1;){k=j;s=-1;for(;++s<p;)r+=(k>>=1);j=(i&((1<<p-1)-1))<<1;}return r;}

Мови OOP, такі як C #, не виграють таку гонку, але я хотів спробувати це. Ось більш прикрашена версія + тестер.

class Program
{
    // Tester: 50 bytes
    static void Main(string[] args)
    {
        int i=2;
        do System.Console.WriteLine($"{i} -> {x(i++)}"); while (i < 12);
        System.Console.Read();
    }
    // Function: 65 bytes (size according to ILDASM.exe)
    static int x(int iOrg)
    {
        int pos, shift, retVal=0, iPrev=iOrg, iTemp;
        pos = System.Convert.ToString(iOrg, 2).Length;
        do {
            iTemp = iPrev; shift = 0;
            do retVal += (iTemp >>= 1); while (++shift < pos);
            iPrev = (iOrg & ((1 << pos - 1) - 1)) << 1;
        } while (--pos > -1); 
        return retVal;
    }
}

Вкладене до-час додає значення iTemp (зрушене праворуч) після встановлення його до тих пір, поки зміна + 1 буде меншою від позиції. У наступному рядку обчислюється наступне зміщене значення iPrev

x1 = 1 << p -1; // 1 << 4 -1 = 8 [1000]
x2 = x1 - 1;    // 8 -  1 = 7    [0111]
x3 = i & x2;    // 1011 & 0111 = 0011 
x4 = x3 << 1;   // 0011 << 1 = 00110
i2 = x4;

x1 і x2 обчисліть маску, x3 застосовує її, а потім зміщує її ліворуч, оскільки остання цифра завжди опускається. Для 11 років це виглядає приблизно так:

START -> _1011[11]
101
10
1   -->  X0110[6], r=0+5+2+1=8
 011
 01
 0  -->  XX110[6], r=8+4=12
  11
  1 -->  XXX10[2], r=12+4=16
   1 ->  XXXX0[X], r=16+1=17

Я знаю, більшість відповідей на C працює також без проблем у C # (@ Tony-Speight працював без проблем), але я це б не вирішив. Крім того, я не дивився на коментарі (ну, крім сміливих заголовків), поки не закінчив сам, тому не було небезпеки зробити це "як C".
DW.com

0

PowerShell v2 +, 138 байт

param($a)$a=[convert]::ToString($a,2);(($b=$a.length-1)..1|%{$l=$_;0..($b-$l+1)|%{[convert]::ToInt32($a.substring($_,$l),2)}})-join'+'|iex

Ун. Перетворення в / з двійкового є дорогим.

Бере введення $a, а потім використовує виклик .NET,[convert]::ToString($a,2) щоб перетворити його на бінарне представлення. Звідти ми проходимо через дві петлі - перша рахується назад від кінця рядка донизу 1, а друга відлічується вгору від 0. (Перший - це те, як довго підтягнеться підрядок, а другий - індекс, де в рядку запустити підрядку.) Ми встановимо помічника $lпо шляху, щоб пройти його до внутрішньої петлі.

Всередині внутрішнього циклу ми використовуємо інший виклик .NET[convert]::ToInt32() для перетворення відповідного .substring()з бази 2в ціле число. Кожен із них залишається на трубопроводі. Ми інкапсулюємо все це з паренами ()та -joinїх разом із a +, а потім відкидаємо це на iex(короткий для Invoke-Expressionта подібний до eval).

Я думаю, що для технічного виклику .NET викликів технічно потрібен v2 або новіший.

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