以-1 + i为基数的加法


64

高斯整数是形式的复数,a+bi其中ab都是整数。在基数-1 + i中,可以使用数字0和唯一地表示所有高斯整数1,而无需使用符号来表示符号。

例如,1100以-1 + i为基数代表十进制数字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,基数-1 + i中的2表示),
  • 代表基数-1 + i的两个二进制整数(例如,十进制120b1100基数-1 + i中的2)
  • 单个字符串由单个非字母数字分隔符分隔两个数字字符串/二进制整数(例如1100 110012,122 + 2)

输出两个高斯整数的和,也以-1 + i为基数,并用数字表示01(以允许输入的一种格式,不一定是相同的选择)。输出允许包含有限数量的前导零。

输入最多30位数字的函数或程序必须在2秒内终止。

其他说明

  • 您可以假定输入不包含无关的前导零。对于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+ii-1的称号。
mbomb007 '16

1
现在我们需要进行另一种转换。:P
Rɪᴋᴇʀ

3
世界上有1100种人。那些了解二进制的人,不懂二进制的人,那些将其与三进制相混淆的人,那些将其与base 4混淆的人,将其与base 5混淆的人,将其与-1 + i混淆的人,将其与base +1混淆的人以6为底数的人,以7为底的人混淆的人,以8为底的人混淆的人,以9为底的人混淆的人...
wizzwizz4

Answers:


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

这会以十进制表示I / O。整数必须用非字母数字字符分隔+

感谢@xnor打高尔夫球2个字节!

Ideone上尝试一下。

这个怎么运作

在“ 复数基数的算术”中,作者展示了如何以-n + i形式的基数加和乘复数。

对于基-1 + i,加法类似于带有进位的常规二进制加法,但有两个区别:

  • 我们没有将1带到下一个较高的位置,而是将110带到了下三个位置。

  • 进位数字可以无限传播。但是,如果没有前导零,则总和a + b最多比ab的最大值多八位。

我们进行如下。

  1. 首先,我们将ab好像它们的数字是十进制数字一样添加。

    对于a = 10101b = 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. 我们总共重复步骤23 d * 8次,其中da + 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倍,由于小号具有尾随大号如果小号是一个整数。


7
这是深奥的魔力input()期望什么格式?(我得到的21112,当我输入10101, 11011。)
蒂姆Pederick

1
没关系; 运行了翻译成Python 3的版本(似乎没有成功),在Python 2下运行良好
蒂姆·派德里克

9
...怎么样。请。说明。
Nic Hartley

@QPaysTaxes我已经编辑了答案。
丹尼斯

@Dennis现在您能解释一下为什么有效吗?例如,为什么d+8不说d+9?怎么样????
Nic Hartley

16

Pyth,34个字节

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

在线尝试:演示测试套件(需要一段时间)。它应该轻松地满足时间限制,因为在线编译器与常规(离线)编译器相比非常慢。

说明:

我的算法基本上是带有加法的实现。但是1,我必须携带110(而不是携带)(1100在base -1+i中与2在base中相同-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

I / O以2为基数的整数完成。

-2感谢@Dennis。


我把它a*a+b*b^58==0ab是逆?这是如何运作的?
xnor

@xnor不,a*a+b*b==58当其中一个为3且另一个为7时
。– feersum

1
(3,7)唯一能给出一个周期并需要特殊外壳的对子对我来说并不明显。如果为true,那么您实际上只需要按(a,b)==(3,7)该顺序检查,因为它会(7,3)递归到(3,7),并且可能会有一个较短的表达式。
xnor

1
现在,肯定会使所有不知道(或忘记)以下内容的人感到困惑:(a)^是XOR,不是幂运算,或(b)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
不,不,这个分数很完美;)
Conor O'Brien

2
分数非常好-2i!
Nic Hartley

哇。当我发布我的解决方案时,我没有看到此解决方案……比我的解决方案优越得多。
Leaky Nun

@KennyLau我只是看着它,然后想着“嗯,我想我应该在某个时候加一个解释……”
Martin Ender

...- 2i?这是十进制,但程序使用的不是十进制。
user75200

12

果冻,29 28 26 24 21 20字节

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

这会以十进制表示I / O。整数必须用非字母数字字符分隔+

在线尝试!验证所有测试用例

背景

在“ 复数基数的算术”中,作者展示了如何以-n + i形式的基数加和乘复数。

对于基-1 + i,加法类似于带有进位的常规二进制加法,但有两个区别:

  • 我们没有将1带到下一个较高的位置,而是将110带到了下三个位置。

  • 进位数字可以无限传播。但是,如果没有前导零,则总和a + b最多比ab的最大值多八位。

我们进行如下。

  1. 首先,我们将ab好像它们的数字是十进制数字一样添加。

    对于a = 10101b = 11011,得出21112

  2. 对于每个大于1的数字,我们必须从该数字中减去2并将110携带到下三个更高的位置。我们可以通过一个十进制数字转换为二进制实现这一点,从基地产生的二进制阵列1100为整数,并解释所得到的列表0的,1 'S,1100年代和1101的作为非规范碱基10数。1个

    对于总和21112,得出21112 + 1098 * 10001 = 21112 + 10981098 = 11002210

  3. 我们总共重复步骤2 d + 8次,其中da + 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个字节

这会执行从最小到最高有效位的数字加法运算(换句话说,就是您在小学教过的完全相同的算法)。区别在于(a)它是二进制而不是十进制,因此每当数字为2或更大时就携带它,而(b)则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]

当然可以打更多的高尔夫球。


您如何确定“零检测器”足够?
Yakk

4
@Yakk:在一个经过同行评审的期刊上,也许给它一个没有反例的例子?
蒂姆·佩德里克

2

视网膜,157个 151 134 133 124 123字节

感谢MartinBüttner,节省了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)

基本上,当大于2时:减去2,在前一位未加任何内容,在前一位加一位,然后在前一位加一位。

用伪代码:

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

一元实现:

每个数字(例如3)显示为xs(例如xxx)的数量,然后以开头0

例如,1234将表示为0x0xx0xxx0xxxx

保留0不变,如101表示0x00x

从最初到最后,只有0and 1,转换很容易由1->0xand进行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,而ri转换的基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;
}

勉强打高尔夫球。它将输入作为一个整数向量,并返回一个整数向量。

现场例子

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.