找到binarray!


24

我们将binarray定义为满足以下属性的数组:

  • 它不是空的
  • 第一个值是 1
  • 最后一个值是 1
  • 所有其他值是01

例如,数组[ 1, 1, 0, 1 ]是有效的binarray

任务

给定一个非负整数的非空数组A和一个正整数N的非空数组,您的工作是找到一个长度为N二进制数组 B,该数组允许通过将不受限制的B个副本的数量相加,再乘以不受限制的B个数量,来生成A。职位。

A = [ 1, 1, 2, 4, 1, 2, 2, 1, 0, 1, 0, 1, 1, 0, 1 ]
N = 4

对于此输入,binarray B = [ 1, 1, 0, 1 ]将是一个有效的答案,因为我们可以这样做:

  [ 1, 1, 0, 1 ]
+       [ 1, 1, 0, 1 ]
+       [ 1, 1, 0, 1 ]
+          [ 1, 1, 0, 1 ]
+                   [ 1, 1, 0, 1 ]
+                                  [ 1, 1, 0, 1 ]
  -----------------------------------------------
= [ 1, 1, 2, 4, 1, 2, 2, 1, 0, 1, 0, 1, 1, 0, 1 ]

规则

  • 输入可以采用任何合理的格式。
  • 输出可以是本机数组(例如[1, 1, 0, 1])或带或不带分隔符的二进制字符串(例如"1,1,0,1""1101"
  • 您只需要打印或返回一个有效的binarray。或者,您可以选择在存在多个解决方案时打印或退回所有这些解决方案。
  • 您不需要支持不会导致任何解决方案的输入。
  • 该和可以包括不与B的任何副本重叠的隐式零。上述总和中的第二个零就是这样的隐式零。
  • 您可以假设A的最大大小为100,B的最大大小为30。
  • 这是代码高尔夫球,因此最短的答案以字节为单位。禁止出现标准漏洞。

测试用例

Input : N = 1 / A = [ 1, 2, 3, 4, 5 ]
Output: [ 1 ]

Input : N = 2 / A = [ 1, 2, 100, 99 ]
Output: [ 1, 1 ]

Input : N = 3 / A = [ 1, 1, 1 ]
Output: [ 1, 1, 1 ]

Input : N = 3 / A = [ 1, 1, 3, 2, 2 ]
Output: [ 1, 1, 1 ]

Input : N = 3 / A = [ 1, 0, 2, 1, 1, 1, 0, 0, 1, 0, 1 ]
Output: [ 1, 0, 1 ]

Input : N = 4 / A = [ 1, 2, 2, 2, 1 ]
Output: [ 1, 1, 1, 1 ]

Input : N = 4 / A = [ 1, 1, 2, 4, 1, 2, 2, 1, 0, 1, 0, 1, 1, 0, 1 ]
Output: [ 1, 1, 0, 1 ]

Input : N = 4 / A = [ 1, 1, 0, 2, 1, 0, 1 ]
Output: [ 1, 0, 0, 1 ] or [ 1, 1, 0, 1 ]

Input : N = 5 / A = [ 1, 3, 6, 9, 8, 6, 3, 4 ]
Output: [ 1, 1, 1, 0, 1 ]

Input : N = 8 / A = [ 2, 1, 0, 2, 3, 3, 1, 2, 1 ]
Output: [ 1, 0, 0, 1, 1, 1, 0, 1 ]

Input : N = 10 / A = [ 1, 2, 1, 2, 2, 1, 3, 3, 3, 2, 3, 0, 2, 1, 1, 0, 1 ]
Output: [ 1, 1, 0, 1, 0, 1, 1, 1, 0, 1 ]

Input : N = 13 / A = [ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 ]
Output: [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ]

Input : N = 5 / A = [ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 ]
Output: [ 1, 1, 1, 1, 1 ]

Input : N = 6 / A = [ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 ]
Output: [ 1, 0, 0, 0, 0, 1 ]

Input : N = 7 / A = [ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 ]
Output: [ 1, 1, 0, 0, 0, 1, 1 ]

Input : N = 9 / A = [ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 ]
Output: [ 1, 0, 1, 0, 1, 0, 1, 0, 1 ]

N应该合理地支持其中最大的价值是什么?
尼尔

@Neil我在A和B上都添加了尺寸限制。–
Arnauld

1
@fənɛtɪk也许吧,但N=4, A = [ 1, 1, 2, 4, 1, 2, 2, 2, 1, 2, 2, 1, 2, 0, 1 ],你会得到30459这是双方11和13,但只有一个整除[ 1, 1, 0, 1 ][ 1, 0, 1, 1 ]是一个有效的答案。
尼尔

1
@ fəˈnɛtɪk这些数字不是以2为底的,所以算术规则不适用。例如,添加时您明确不能携带。
圆珠笔本

2
请添加这些测试用例,它们似乎几乎破坏了所有已发布的答案:N = 3,A = [1、0、2、0、2、0、1],输出= [1、0、1];N = 3,A = [1,1,1,0,0,0,1,1,1],输出= [1,1,1]。
Anders Kaseorg

Answers:


8

PHP,105 92 90 86字节

约尔格固定解决方案

for($b=1+2**$argv[1];;)--$argc>1?$s+=$argv[$argc]*2**$i++:$s%($b-=2)||die(decbin($b));

需要N从第一命令行参数,在这之后的值; 在线运行-r测试
打印二进制数(格式10001);如果没有有效的解决方案,则打印无效的解决方案或将其耗尽。

第一个版本(现在为97个字节),对于无效输入不打印任何内容:在线测试

for($b=1+$m=2**$argv[1];$m/2<=$b;)--$argc>1?$s+=$argv[$argc]*2**$i++:$s%($b-=2)||die(decbin($b));

分解

for($b=1+$m=2**$argv[1];$m/2<=$b;)  # second loop: loop $b from 2^N-1 by -2 to 2^(N-1)
--$argc>1                           # first loop: decrease $argc ...
    ?$s+=$argv[$argc]*2**$i++           # while $argc>1: binary sum from last to 2nd argument
    :$s%($b-=2)||die(decbin($b));       # later: if $b divides $s, print in binary and exit

很好,您无法达到100以下的字节数吗?
约尔格Hülsermann

1
@JörgHülsermann我可以。
泰特斯(Titus)

沉思。在此之前,我知道您会更好。我希望你能保持最低的字节数
约尔格Hülsermann

1
在N = 3,A = [1、0、2、0、2、0、1]时,这会错误地返回111,其中唯一正确的结果是[1、0、1]。
Anders Kaseorg

8

PHP,219字节

<?for(list($g,$z)=$_GET,$d=~-$l=2**$z;$d>=$l/2;max(array_diff_assoc($r,$g)?:[0])?:$o[]=$b,$d-=2)for($r=[],$b=decbin($d),$k=0;$k<count($g);$k++)for($u=$g[$k]-$r[$k],$i=0;$i<$z;$i++)$u<1?:$r[$k+$i]+=$u*$b[$i];print_r($o);

在线尝试!

使用[$g,$z]=$_GETPHP 7.1代替-4字节list($g,$z)=$_GET


似乎它同时输出有效([1,0,1,0,1,0,1,0,1])和无效答案([1,0,0,0,1,0,1,1,1]为最后一个测试用例)。
Arnauld

-8个字节:while($_GET[0])$s+=2**$i++*array_pop($_GET[0]);。-5个字节:range(1|.5*$m=2**$_GET[1],$m,2)
泰特斯

@Arnauld是的,我应该给作为输出只有最高binarray也使这个解决方案有效
约尔格Hülsermann

2
@ fəˈnɛtɪk我确实同意你的数学,但是挑战在于找到一种可以精确地加到A,而不是等效安排的模式。在这里,我们得到[ 1,0,1,1,1,0,2,2,2,2,2,1 ]
Arnauld

1
-1个字节,带有for($g=$_GET[0];$g;)
泰特斯(Titus)

3

Python,166个字节

def f(a,n):
 for i in range(1<<n-1,1<<n):
  b=bin(i)[2:];u,v=(int(('0{:0>%d}'%sum(a)*len(s)).format(*s))for s in[a,b])
  if u%v<1>int(str(u//v*10)[::~sum(a)]):yield b

在线尝试!

怎么运行的

考虑A和B作为基本的数字ķ号码Úv。例如(我们将使用k = 1000进行说明):

A = [1、2、1、3、2、1、2]
B = [ 1、0、0、1 ]
u = 1 002 001 003 002 001 002
v = 1 000 000 001

正如许多其他答复者所注意到的那样,如果B是有效答案,则u可被v整除。在这种情况下,

û = 1 002 001 002⋅ v

这个商数被转换回数组[1、2、1、2],可以准确地告诉我们需要转移到每个位置的B的副本数。

  [1, 0, 0, 1]
+    [1, 0, 0, 1]
+    [1, 0, 0, 1]
+       [1, 0, 0, 1]
+          [1, 0, 0, 1]
+          [1, 0, 0, 1]
-----------------------
  [1, 2, 1, 3, 2, 1, 2]

(为什么?因为这正是乘法在基数k中工作的时间。)

其他答复者没有注意到的是 上述条件还不够。例如:

A = [1、2、1、3、2、1、2]
B = [ 1、1、1、1 ]
u = 1 002 001 003 002 001 002
v = 1 001 001 001
u = 1 000 999 002⋅ v

从数学上讲,我们仍然可以将商数转换回数组[1,1,-1,2],如果允许我们使用B的负副本,则可以很好地工作:

  [1, 1, 1, 1]
+    [1, 1, 1, 1]
       [1, 1, 1, 1]
+          [1, 1, 1, 1]
+          [1, 1, 1, 1]
-----------------------
  [1, 2, 1, 3, 2, 1, 2]

但是当然,挑战赛不允许出现负面副本。因此,我们需要额外的检查。

为此,我们选择一个基数k = 10 e,其中k > 10⋅sum(A),并在将商乘以10时检查是否没有基数k溢出到下一个基数k。即,在商乘以10的以10为底的十进制表示中,从结尾开始的每第e个基数十进制数都必须为0。这保证了该商转换回具有非负元素的数组。


1
我喜欢您使用10的大幂作为基准以简化基准转换的技巧。
尼尔

2

PHP,213字节

有点打高尔夫球

<?for($b=2**~-$l=$_GET[1];$b<2**$l;array_filter($t[$b++])?:$d[]=$o)for($g=count($t[$b]=$_GET[$i=0]);min($t[$b])>-1&$i<=$g-$l;$i++)for($e=$t[$b][$i],$k=0,$o=decbin($b);$k<$l;)$t[$b][$k+$i]-=$o[$k++]*$e;print_r($d);

在线尝试!

PHP,344字节首次使用

在我的第一个答案之后,我决定做出更长的尝试,以退还所有有效的解决方案。

<?foreach(range(2**($l=$_GET[1])-1,2**($l-1))as$b){$t[$b]=($g=$_GET[0]);for($i=0;$t[$b]&&$i<=count($g)-$l;$i++){$e=reset($y=array_slice($t[$b],$i,$l));foreach(str_split(decbin($b))as$k=>$v)$t[$b][$k+$i]=$y[$k]-$e*$v;if(min($t[$b])<0)unset($t[$b]);}}foreach($t as$k=>$v)if(max($v)>0)unset($t[$k]);echo join(",",array_map(decbin,array_keys($t)));

在线版本

分解

foreach(
    range(2**($l=$_GET[1])-1
    ,2**($l-1)
    ) # make decimal range of a binarray with given length
    as$b){
$t[$b]=($g=$_GET[0]); # make a copy for each possible solution pattern
    for($i=0;$t[$b]&&$i<=count($g)-$l;$i++){ # Loop till solution is valid or reach last digit
        $e=reset($y=array_slice($t[$b],$i,$l)); # take first value of a sequence with the length
        foreach(str_split(decbin($b))as$k=>$v)
            $t[$b][$k+$i]=$y[$k]-$e*$v; # replace values in copy
        if(min($t[$b])<0)unset($t[$b]); # kill solution if a minimum <0 exists
    }
}
foreach($t as$k=>$v)if(max($v)>0)unset($t[$k]); # drop all solutions where the sum is not zero 


echo join(",",array_map(decbin,array_keys($t))); #Output all solutions

这似乎适用于N≥2,但在N = 1情况下失败,例如挑战中的第一个测试情况。
Anders Kaseorg

@AndersKaseorg现在它支持N = 1例只需要设置一个=在较短的版本。在它需要删除四个字节越大版本第一环路
约克Hülsermann

1

Python,205个字节

def f(a,l):
 b=lambda s:b(s[:-1])*sum(a)*8+int(s[-1])if s else 0
 c=lambda n:n and(n/sum(a)/4%2 or c(n/sum(a)/8))
 for i in range(2**~-l,2**l):
  j=bin(i)[2:]
  if b(a)%b(j)<1 and not c(b(a)/b(j)):return j

返回不带分隔符的二进制字符串。正如@AndersKaseorg所指出的那样,对于@ fəˈnɛtɪk的解决方案,某些输入不起作用,因为除法表示负系数是不允许的。要解决此问题,我使用了一个很大的基础并测试该部门中是否没有借贷。


好的,我认为这是一个实际的反例:f([1, 1, 1, 0, 0, 0, 1, 1, 1], 3)错误地返回101
Anders Kaseorg

@AndersKaseorg嗯,反转循环顺序是否有帮助,还是算法从根本上仍然无效?
尼尔

我认为,从根本上来说,它没有任何检查就可以解决。反向变体失败f([1, 0, 2, 0, 2, 0, 1], 3),并且正向和反向变体都失败f([1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0], 5)
Anders Kaseorg

即使您检查是否i为奇数,正向和反向变体都将失败f([1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]*10, 5)
Anders Kaseorg

1
@AndersKaseorg嗯,是的,当gcd(k,n)= 1时,(x^kn-1)/(x^k-1)总是有(x^n-1)/(x-1)一个因数,愚弄@ fəˈnɛtɪk在任何基础上的解。
尼尔

1

Pyth,32个字节

f!|%FKiRJysQ,QT>#sQj/FKJ+L1^U2tE

在线尝试

怎么运行的

                           ^U2tE   Cartesian power [0, 1]^(N - 1)
                        +L1        prepend 1 to every list
f                                  filter for lists T such that:
          sQ                         sum(A)
         y                           double
        J                            assign to J
      iR    ,QT                      convert [A, T] from base J
     K                               assign to K
   %F                                fold modulo
  |                                  logical OR with
                    /FK                fold integer division over K
                   j   J               convert to base J
               >#sQ                    filter for digits greater than sum(A)
 !                                   logical NOT

该策略与我的Python答案相似,不同之处在于,由于Pyth具有用于基本转换的内置函数,我们可以使用更有效的基本k = 2⋅sum (A),并直接检查商的每个数字最多为sum(A )。


1

Pari / GP77 74 96 80字节

n->a->[v|d<-divisors(b=Pol(a)),(v=Vec(d))%2==v&&vecmin(Vec(b/d))>=0&&d%x&&#d==n]

返回所有解决方案。

首先将数组a转换为多项式b。然后从除数选择b多项式d,使得系数d10和的系数b / d都是非负,和d(0) = 1,和deg(d) = n + 1。最后,将它们转换回数组。

在线尝试!

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.