Encontre o binarray!

24

Definimos um binarray como uma matriz que satisfaz as seguintes propriedades:

  • não está vazio
  • o primeiro valor é um 1
  • o último valor é um 1
  • todos os outros valores são 0ou1

Por exemplo, a matriz [ 1, 1, 0, 1 ]é um binarray válido .

A tarefa

Dada uma matriz não vazia A de números inteiros não negativos e um número inteiro positivo N , sua tarefa é encontrar um binarray B de comprimento N que permita gerar A somando um número irrestrito de cópias de B , deslocadas por um número irrestrito de posições.

Exemplo

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

Para esta entrada, o binarray B = [ 1, 1, 0, 1 ] seria uma resposta válida porque podemos fazer:

  [ 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 ]

Regras

  • A entrada pode ser obtida em qualquer formato razoável.
  • A saída pode ser uma matriz nativa (por exemplo [1, 1, 0, 1]) ou uma string binária com ou sem um separador (por exemplo "1,1,0,1"ou "1101")
  • Você só precisa imprimir ou devolver um binarray válido . Como alternativa, você pode optar por imprimir ou devolver todos eles quando existirem várias soluções.
  • Você não precisa dar suporte a entradas que não levam a nenhuma solução.
  • A soma pode incluir zeros implícitos que não se sobreponham com qualquer cópia de B . O segundo zero na soma acima é um zero tão implícito.
  • Você pode assumir que o tamanho máximo de A é 100 e o tamanho máximo de B é 30.
  • Isso é código-golfe, então a resposta mais curta em bytes vence. As brechas padrão são proibidas.

Casos de teste

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 ]
Arnauld
fonte
Qual o maior valor Ndisso que deve ser razoavelmente suportado?
Neil
@Neil Eu adicionei limites de tamanho em ambos A e B.
Arnauld
11
@ fənɛtɪk Talvez, mas para N=4, A = [ 1, 1, 2, 4, 1, 2, 2, 2, 1, 2, 2, 1, 2, 0, 1 ], você tem 30459 que é divisível por ambos 11 e 13 ainda apenas um dos [ 1, 1, 0, 1 ]e [ 1, 0, 1, 1 ]é uma resposta válida.
Neil
11
@ fəˈnɛtɪk Estes números não estão escritos na base 2, portanto as regras de aritmética não se aplicam. Por exemplo, você explicitamente não pode carregar ao adicionar.
usar o seguinte
2
Por favor, adicione estes casos de teste, que parecem quebrar quase todas as respostas postadas: N = 3, A = [1, 0, 2, 0, 2, 0, 1], output = [1, 0, 1]; N = 3, A = [1, 1, 1, 0, 0, 0, 1, 1, 1], saída = [1, 1, 1].
Anders Kaseorg

Respostas:

8

PHP, 105 92 90 86 bytes

A solução da Jörg fixa e golfada:

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

pega Nno primeiro argumento da linha de comando, valores depois disso; executar -rou testá-lo online .
imprime número binário (formato 10001); imprime uma solução inválida ou fica sem energia se não houver uma solução válida.

primeira versão (agora 97 bytes) que não imprime nada para entrada inválida: teste on-line

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

demolir

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
Titus
fonte
Bom, você não conseguiu alcançar uma contagem de bytes abaixo de 100?
Jörg Hülsermann 30/03
11
@ JörgHülsermann eu poderia.
Titus
Pensamento pesado. Sei antes disso que você é melhor. Eu espero que você pode segurar o menor contagem de bytes
Jörg Hülsermann
11
Em N = 3, A = [1, 0, 2, 0, 2, 0, 1], isso retorna incorretamente111 onde o único resultado correto é [1, 0, 1].
Anders Kaseorg 2/06
8

PHP , 219 bytes

<?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);

Experimente online!

-4 bytes usando [$g,$z]=$_GETPHP 7.1 em vez delist($g,$z)=$_GET

Jörg Hülsermann
fonte
Parece que gera [1,0,1,0,1,0,1,0,1]uma resposta válida ( ) e inválida ( [1,0,0,0,1,0,1,1,1]) para o último caso de teste.
Arnauld 30/03
-8 bytes: while($_GET[0])$s+=2**$i++*array_pop($_GET[0]);. -5 bytes: range(1|.5*$m=2**$_GET[1],$m,2).
Titus
@Arnauld Sim eu deveria dar como saída apenas a mais alta binarray também fazer esta solução válida
Jörg Hülsermann
2
@ f withnɛtɪk Eu concordo com sua matemática, mas o desafio é encontrar um padrão que possa ser resumido exatamente a A, e não um arranjo equivalente. Aqui, nós teríamos [ 1,0,1,1,1,0,2,2,2,2,2,1 ].
Arnauld
11
-1 byte com for($g=$_GET[0];$g;).
Titus
3

Python, 166 bytes

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

Experimente online!

Como funciona

Considere A e B como os dígitos da base k números u e v . Por exemplo (usaremos k = 1000 para ilustração):

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

Como muitos dos outros respondentes notaram, se B é uma resposta válida, u é divisível por v . Nesse caso,

u = 1 002 001 002 ⋅ v

Esse quociente, traduzido de volta para a matriz [1, 2, 1, 2], nos diz exatamente quantas cópias de B precisamos para cada posição.

  [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]

(Por quê? Porque é exatamente assim que a multiplicação funciona na base k .)

O que os outros respondentes não perceberam é que a condição acima não é suficiente . Por exemplo:

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

Matematicamente falando, ainda podemos converter esse quociente de volta para a matriz [1, 1, -1, 2], que funciona bem se tivermos permissão para usar cópias negativas de 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]

mas é claro que o desafio não permite cópias negativas. Então, precisamos de uma verificação adicional.

Para esse fim, selecionamos uma base k = 10 e onde k > 10 ⋅ soma (A) e verificamos que nenhum dos dígitos base k transborda para o próximo dígito base k quando multiplicamos o quociente por dez. Isto é, cada e th dez dígitos de base, a partir da extremidade, na representação base dez vezes o quociente de dez, deve ser 0. Isto garante que o quociente traduz volta para uma matriz com elementos não negativos.

Anders Kaseorg
fonte
11
Adoro o seu truque de usar uma grande potência de 10 como base para facilitar a conversão da base.
Neil
2

PHP, 213 bytes

Da mesma forma um pouco de golfe

<?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);

Experimente online!

PHP, 344 bytes trabalhando pela primeira vez

Após minha primeira resposta, decidi fazer uma tentativa mais longa que devolvesse todas as soluções válidas.

<?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)));

Versão Online

Demolir

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
Jörg Hülsermann
fonte
Isso parece funcionar para N ≥ 2, mas falha em casos N = 1, como o primeiro caso de teste no desafio.
Anders Kaseorg 4/17
@AndersKaseorg Agora ele suporta o N = 1 casos, só precisa definir um =no primeiro loop para a versão mais curta Na versão maior ele precisa eliminar quatro Bytes
Jörg Hülsermann
1

Python, 205 bytes

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

Retorna uma string binária sem separador. Como o @AndersKaseorg aponta, existem entradas para as quais a solução do @ fəˈnɛtɪk não funciona porque a divisão representa um coeficiente negativo que não é permitido. Para contornar isso, uso uma base muito grande e testo que não há empréstimos na divisão.

Neil
fonte
Ok, acho que este é um contra-exemplo real: f([1, 1, 1, 0, 0, 0, 1, 1, 1], 3)retorna incorretamente 101.
Anders Kaseorg
@AndersKaseorg Hmm, reverter a ordem do loop ajuda ou o algoritmo ainda está fundamentalmente quebrado?
Neil
Eu acho que é fundamentalmente quebrado sem verificações adicionais. A variante reversa falha f([1, 0, 2, 0, 2, 0, 1], 3)e as variantes direta e reversa falham f([1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0], 5).
Anders Kaseorg
E mesmo que você verifique isso i, as variantes de avanço e reversão falham f([1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]*10, 5).
Anders Kaseorg
11
@AndersKaseorg Ah, sim, quando gcd (k, n) = 1 (x^kn-1)/(x^k-1)sempre tem (x^n-1)/(x-1)como um fator que engana a solução do @ f @nɛtɪk em qualquer base.
Neil
1

Pitão, 32 bytes

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

Experimente online

Como funciona

                           ^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

A estratégia é semelhante à minha resposta do Python , exceto que, como o Pyth possui embutidos para a conversão de base, podemos usar uma base mais eficiente k = 2 ⋅ soma (A) e verificar diretamente se cada dígito do quociente é no máximo (A )

Anders Kaseorg
fonte
1

Pari / GP , 77 74 96 80 bytes

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

Retorna todas as soluções.

Primeiro converte a matriz aem um polinômio b. Em seguida, escolhe dos divisores bos polinômios de dmodo que os coeficientes de dsão todos 1e 0, e os coeficientes de b / dsão todos não-negativos, e d(0) = 1, e deg(d) = n + 1. Por fim, converte-os novamente em matrizes.

Experimente online!

alefalpha
fonte