Дополнение в базе -1 + я


64

Гауссовы целые числа являются комплексными числами вида, a+biгде aи bоба являются целыми числами. В основании -1 + i все гауссовы целые числа могут быть уникально представлены с использованием цифр 0и 1без необходимости обозначения знака символом.

Например, 1100в базе -1 + я представляет десятичное число 2, так как

1*(-1+i)^3 + 1*(-1+i)^2 + 0*(-1+i)^1 + 0*(-1+i)^0
= (2+2i) + (-2i) + 0 + 0
= 2

Входными данными будут два гауссовых целых числа в основании -1 + i, представленные с помощью цифр 01. Это может принимать одну из следующих форм:

  • Две отдельные строки цифр,
  • Два десятичных целых числа, состоящие из 01представления базовых чисел -1 + i (например, 1100для 2 в базовых -1 + i),
  • Два двоичных целых числа, представляющих базовые числа -1 + i (например, десятичные 12или 0b11002 в основании -1 + i)
  • Одна строка, разделяющая две строки из цифр / двоичные целые числа одним не алфавитно-цифровым разделителем (например, 1100 1100или 12,12для 2 + 2)

Выведите сумму двух гауссовых целых чисел, также в базе -1 + i и представленных с использованием цифр 01(в одном из форматов, разрешенных для ввода, не обязательно того же выбора). Вывод может содержать конечное число ведущих нулей.

Ваша функция или программа должны завершиться в течение 2 секунд для входов не более 30 цифр каждый.

Дополнительные разъяснения

  • Вы можете предположить, что входные данные не содержат посторонних начальных нулей. Для особого случая 0 вы можете выбрать либо 0пустую строку, либо как представление.

Контрольные примеры

0, 0 => 0                                      # 0 + 0 = 0
0, 1 => 1                                      # 0 + 1 = 1
1, 1 => 1100                                   # 1 + 1 = 2
1100, 1100 => 111010000                        # 2 + 2 = 4
1101, 1101 => 111011100                        # 3 + 3 = 6
110111001100, 1110011011100 => 0               # 42 + (-42) = 0
11, 111 => 0                                   # i + (-i) = 0
11, 110 => 11101                               # i + (-1-i) = -1
10101, 11011 => 10010                          # (-3-2i) + (-2+3i) = (-5+i)
1010100101, 111101 => 1110100000100            # (-19+2i) + (3-4i) = (-16-2i)

Более длинные тестовые случаи:

11011011010110101110010001001, 111100010100101001001010010101 => 0
111111111111111111111111111111, 111111111111111111111111111111 => 100100100100100100100100100100
101101110111011101110111011101, 101101110111011101110111011101 => 11101001010001000100010001000100011100
100100010101001101010110101010, 100010011101001011111110101000 => 110000110010101100001100111100010

Нет цифровых списков?
CalculatorFeline

@CatsAreFluffy Нет цифровых списков, извините.
Sp3000

96
Вы можете сохранить один байт путем изменения -1+iв i-1в названии.
mbomb007

1
Теперь нам нужно преобразование наоборот. : P
Rɪᴋᴇʀ

3
В мире 1100 типов людей. Те, кто понимает двоичный код, те, кто не понимает, те, кто путает его с троичным, те, кто путает его с базой 4, те, кто путает его с базой 5, те, кто путает его с базой -1 + i, те, кто путает его с база 6, те, кто путает с базой 7, те, кто путает с базой 8, те, кто путает с базой 9 ...
wizzwizz4

Ответы:


42

Python 2, 98 97 91 84 байта

s=input();L=1
for _ in`s`*8:s+=1098*int(str(s).translate('0011'*64));L*=10
print s%L

Это делает ввод / вывод в десятичном формате. Целые числа должны быть разделены не алфавитно-цифровым символом +.

Спасибо @xnor за 2 байта!

Попробуйте это на Ideone .

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

В Арифметике в комплексных основаниях автор показывает, как сложить и умножить комплексные числа в базисах вида -n + i .

Для базы -1 + i сложение выполняется аналогично обычному двоичному сложению с переносом, с двумя отличиями:

  • Вместо того, чтобы переносить 1 на следующую более высокую позицию, мы переносим 110 на следующие три.

  • Переносимые цифры могут распространяться бесконечно. Однако без начальных нулей сумма a + b имеет максимум на восемь цифр больше, чем максимум a и b .

Мы действуем следующим образом.

  1. Сначала мы добавляем a и b, как если бы их цифры были десятичными.

    Для a = 10101 и b = 11011 это дает 21112 .

  2. Затем мы формируем новое число, заменяя цифры больше 1 на 1 , другие на 0 . 1

    На сумму 21112 это дает 10001 .

  3. Для каждой цифры больше 1 мы должны вычесть 2 из этой цифры и перенести 110 в следующие три более высокие позиции. Поскольку 1098 = 10 * 110 - 2 , мы можем добиться этого, умножив результат шага 2 на 1098 , а затем добавив этот продукт к сумме. 2

    Для суммы 21112 это дает 21112 + 1098 * 10001 = 21112 + 10981098 = 11002210 .

  4. Мы повторяем шаги 2 и 3 всего d * 8 раз, где d - количество цифр a + b . 3

    Для начальной суммы 21112 результаты

                          11002210
                          12210010
                        1220010010
                      122000010010
                    12200000010010
                  1220000000010010
                122000000000010010
              12200000000000010010
            1220000000000000010010
          122000000000000000010010
        12200000000000000000010010
      1220000000000000000000010010
    122000000000000000000000010010
                                 .
                                 .
                                 .
    
  5. Мы берем окончательную сумму по модулю 10 d + 8 , отбрасывая все, кроме последних d + 8 цифр.

    Для начальной суммы 21112 конечный результат равен 10010 .


1 Это достигается с помощью перевода . Повторение строки 0011 64 раза приводит к тому, что одна строка повторения совпадает с последовательностью символов ASCII 0123 , достигая желаемой замены.

2 Обратите внимание, что цифры этой суммы не могут превышать 3 (начальное значение 1 плюс два 1 от переносов).

3 Это работает для d = 1 , а d * 8> d + 8 в противном случае. Код может повторить шаги (D + 1) * 8 раз, так как с имеет косую L , если s является длиной целого числа.


7
Это глубокая магия . Какой формат input()ожидает? (Я получаю, 21112когда я 10101, 11011
вхожу

1
Неважно; на котором была запущена версия, переведенная (кажется, безуспешно) на Python 3. Она отлично работает под Python 2 .
Тим Педерик

9
...Как. Пожалуйста. Объясните.
Ник Хартли

@QPaysTaxes Я отредактировал свой ответ.
Деннис

@ Денис Теперь не могли бы вы объяснить, почему это работает? Например, почему, d+8а не, скажем d+9,? Как????
Ник Хартли

16

Pyth, 34 байта

_shM.u,%J/eMeN\12-+PMeNm.B6/J2k,kQ

Попробуйте онлайн: демонстрация или тестовый набор (занимает довольно много времени). Он должен удовлетворять ограничению по времени, хотя и легко, поскольку онлайн-компилятор довольно медленный по сравнению с обычным (автономным) компилятором.

Объяснение:

Мой алгоритм в основном представляет собой реализацию сложения с переносом. Но вместо того 1, чтобы нести, я должен нести 110( 1100в базе так -1+iже, как 2в базе -1+i). Это работает в основном нормально, но вы можете застрять в бесконечных циклах печати нулей. Например, если вы добавляете 1с 11и в настоящее время имеете перенос 110. Поэтому я в основном добавляю, пока не застряну в цикле, а затем остановлюсь. Я думаю, что цикл, который будет всегда печатать нули, и поэтому это должно быть хорошо.

_shM.u,%J/eMeN\12-+PMeNm.B6/J2k,kQ   implicit: Q = input list of strings
                               ,kQ   create the pair ["", Q]
    .u                               modify the pair N (^) until loop:
      ,                                replace N with a new pair containing:
            eN                           N[1] (the remaining summand)
          eM                             take the last digits of each summand
         /    \1                         count the ones
        J                                store the count in J
       %J       2                        J % 2 (this is the first element of the new pair)
                   PMeN                  remove the last digit of each summand
                  +    m   /J2           and add J / 2 new summand:
                        .B6                 with the value "110" (binary of 6)
                 -            k          remove empty summand
    .u                               returns all intermediate results
  hM                                 extract the digits
 s                                   sum them up to a long string
_                                    reverse

13

Python 2, 69 67 байт

f=lambda a,b:a*a+b*b^58and 2*f(a*b%2*6,f(a/2,b/2))|a+b&1if a else b

Ввод / вывод выполняется с целыми числами из базы 2.

-2 спасибо @Dennis.


Я беру это a*a+b*b^58==0когда aи bобратные? Как это работает?
xnor

@xnor Нет, a*a+b*b==58когда одному из них 3, а другому 7
feersum

1
Мне не очевидно, что (3,7)это единственная пара, которая дает цикл и нуждается в специальном корпусе. Если это так, то вам нужно проверить только (a,b)==(3,7)в этом порядке, так как (7,3)рекурсивно (3,7), и, возможно, есть более короткое выражение для этого.
xnor

1
Теперь это гарантированно смущает любого, кто не знает (или забывает), что (а) ^это XOR, а не возведение в степень, или (б) XOR имеет более низкий приоритет, чем +.
Тим Педерик

12

Сетчатка , 100 байт

r+`(.*)(\d|(?!\4))( .*)(.?)
$2$4:$1$3
T` 0
+`1:11(1*:1*)11
:$1
^:*
:::
}`:(1*:1*:)11
1:1$1
(1)*:
$#1

Это берет ввод, разделенный запятой. Выход всегда начинается с трех ведущих нулей.

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

Мне действительно интересно, есть ли более короткое решение для первого этапа ...


2
Нет, нет, оценка прекрасна как она есть;)
Конор О'Брайен

2
Хороший счет -2i!
Ник Хартли

Ух ты. Я не видел это решение, когда я опубликовал мое ... Гораздо лучше, чем мое решение.
Утренняя монахиня

@KennyLau Я просто смотрел на это и думал: «Хм, наверное, мне следовало добавить объяснение в какой-то момент ...»
Мартин Эндер,

...- 2i? Это десятичное число, но программа использует базу, которой нет.
user75200

12

Желе, 29 28 26 24 21 20 байт

DBḅ1100ḌµDL+8µ¡Dṣ2ṪḌ

Это делает ввод / вывод в десятичном формате. Целые числа должны быть разделены не алфавитно-цифровым символом +.

Попробуйте онлайн! или проверьте все контрольные примеры .

Фон

В Арифметике в комплексных основаниях автор показывает, как сложить и умножить комплексные числа в базисах вида -n + i .

Для базы -1 + i сложение выполняется аналогично обычному двоичному сложению с переносом, с двумя отличиями:

  • Вместо того, чтобы переносить 1 на следующую более высокую позицию, мы переносим 110 на следующие три.

  • Переносимые цифры могут распространяться бесконечно. Однако без начальных нулей сумма a + b имеет максимум на восемь цифр больше, чем максимум a и b .

Мы действуем следующим образом.

  1. Сначала мы добавляем a и b, как если бы их цифры были десятичными.

    Для a = 10101 и b = 11011 это дает 21112 .

  2. Для каждой цифры больше 1 мы должны вычесть 2 из этой цифры и перенести 110 в следующие три более высокие позиции. Мы можем добиться этого, преобразовав каждую десятичную цифру в двоичную, получившиеся двоичные массивы из основания 1100 в целое число, и интерпретировать полученный список 0 , 1 , 1100 и 1101 как неканоническую основу 10 номер. 1

    Для суммы 21112 это дает 21112 + 1098 * 10001 = 21112 + 10981098 = 11002210 .

  3. Мы повторяем шаги 2 всего d + 8 раз, где d - количество цифр a + b .

    Для начальной суммы 21112 результаты

                          11002210
                          12210010
                        1220010010
                      122000010010
                    12200000010010
                  1220000000010010
                122000000000010010
              12200000000000010010
            1220000000000000010010
          122000000000000000010010
        12200000000000000000010010
      1220000000000000000000010010
    122000000000000000000000010010
    
  4. Мы отбрасываем все, кроме последних d + 8 цифр из конечного результата. Это достигается путем отказа от всего после последних 2 . 2

    Для начальной суммы 21112 конечный результат равен 10010 .

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

DBḅ1100ḌµDL+8µ¡Dṣ2ṪḌ  Main link. Argument: a + b (implicit sum)

        µ    µ¡       Execute the chain before the first µ n times, where n is
                      the result of executing the chain before the second µ.
         D            Convert a + b to base 10.
          L           Length; count the decimal digits.
           +8         Add 8 to the number of digits.
D                     Convert the initial/previous sum to base 10.
 B                    Convert each digit (0 - 3) to binary.
  ḅ1100               Convert each binary array from base 1100 to integer.
       Ḍ              Interpret the resulting list as a base 10 number.
               D      Convert the final sum to base 10.
                ṣ2    Split at occurrences of 2.
                  Ṫ   Select the last chunk.
                   Ḍ  Convert from base 10 to integer.

1 Обратите внимание, что цифры этой суммы не могут превышать 3 (начальное значение 1 плюс два 1 от переносов).

2 Это работает, потому что последняя цифра, которая будет отменять, не может быть 3 .


6

Python 3, 289 байт

При этом выполняется сложение цифр от младшей к старшей значащей (иными словами, точно такой же алгоритм, которому вас учили в начальной школе). Различия в том, что (а) он в двоичном, а не в десятичном виде, поэтому вы носите, когда цифра составляет 2 или более, и (б) 1 + 1 = 1100нет 10.

На самом деле, также необходимо отметить, что в 11 + 111 = 0противном случае суммы, которые должны стать нулевыми, никогда не прекратятся.

from collections import*
def a(*s,p=0):
 r=defaultdict(int,{0:0})
 for S in s:
  n=0
  for d in S[::-1]:r[n]+=d=='1';n+=1
 while p<=max(r):
  while r[p]>1:
   r[p]-=2
   if r[p+1]>1<=r[p+2]:r[p+1]-=2;r[p+2]-=1
   else:r[p+2]+=1;r[p+3]+=1
  p+=1
 return str([*map(r.get,sorted(r))])[-2::-3]

Больше игры в гольф, безусловно, возможно.


Насколько вы уверены, что ваш «нулевой детектор» достаточен?
Якк

4
@Yakk: По шкале от одного до рецензируемого журнала, может быть, пока нет контрпримеров?
Тим Педерик

2

Сетчатка, 157 151 134 133 124 123 байта

1 байт благодаря Мартину Бюттнеру.

(.+),(.+)
$.1$*0$2,$.2$*0$1,
1
0x
+`(0x*)(,.*)0(x*),
$2,$1$3
{`,

(^|0x0xx0xx)
000
(0x*)(0x*)(0x*0)xx
$1x$2x$3
)`^0+
0
0x
1

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

Преобразует в унарный, а затем повторите следующие замены (показано здесь в десятичном виде):

122 -> 000
0002 -> 1100 (this can also be 0012 -> 1110 and 1112 -> 2210 or even 2222 -> 3320 or even 3333 -> 4431)

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

В псевдокоде:

if(a[n]>2):
    a[n] -= 2;
    a[n-2] += 1;
    a[n-3] += 1;

Унарная реализация:

Каждая цифра (например 3) отображается как число xs (например xxx), а затем с префиксом 0.

Например, 1234будет выражено как 0x0xx0xxx0xxxx.

Это оставляет 0без изменений, как 101было бы выражено 0x00x.

Поскольку изначально и, наконец, есть только 0и 1, преобразование может быть легко сделано с помощью 1->0xи 0x->1.

Нажмите здесь, чтобы увидеть каждый шаг .


1

JavaScript (ES6), 146 126 байт

r=n=>n&&n%2-r(n>>=1)-i(n)
i=n=>n&&r(n>>=1)-i(n)
g=(x,y,b=(x^y)&1)=>x|y&&b+2*g(b-x+y>>1,b-x-y>>1)
(x,y)=>g(r(x)+r(y),i(x)+i(y))

gпреобразует гауссово целое число (действительные и мнимые части) в основание i-1, а rи iпреобразует базовое i-1целое число в гауссово число (действительные и мнимые части соответственно). Как только преобразования будут сделаны, я просто должен сделать арифметику.

Изменить: 20 байтов сохранены путем вычисления реальной и мнимой частей отдельно.


1

C ++ 416 байт, плюс #include <vector>\n#include <algorithm>\n(еще 40)

using I=int;using v=std::vector<I>;void r(v&x){v r{rbegin(x),rend(x)};x=r;}v a(v L,v R){r(L);r(R);L.resize(std::max(L.size(),R.size()));for(int&r:R)L[&r-R.data()]+=r;while(1){L.resize(L.size()+3);auto it=find(rbegin(L),rend(L),2);if(it==rend(L))break;I i=-1+it.base()-begin(L);i&&L[i+1]&&L[i-1]/2?L[i+1]=L[i]=L[i-1]=0:(++L[i+2],++L[i+3],L[i]=0);}L.erase( std::find(rbegin(L),rend(L),1).base(),end(L));r(L);return L;}

или с большим количеством пробелов:

using I=int;
using v=std::vector<I>;

void r(v&x){v r{rbegin(x),rend(x)};x=r;}
v a(v L,v R) {
  r(L);r(R);
  L.resize(std::max(L.size(),R.size()));
  for(int&r:R)
    L[&r-R.data()]+=r;
  while(1) {
    L.resize(L.size()+3);
    auto it=find(rbegin(L), rend(L), 2);
    if(it==rend(L)) break;
    I i=-1+it.base()-begin(L);
    i&&L[i+1]&&L[i-1]/2?
      L[i+1]=L[i]=L[i-1]=0
    :
      (++L[i+2],++L[i+3],L[i]=0);
  }
  L.erase( std::find(rbegin(L),rend(L),1).base(), end(L));
  r(L);
  return L;
}

Еле гольф. Он принимает входные данные как вектор целых и возвращает вектор целых.

Живой пример .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.