Divida e divida e conquiste


22

Às vezes, quando estou ociosamente tentando fatorar qualquer número que aparece na minha frente after, depois de um tempo percebo que é mais fácil do que eu pensava. Tome 2156por exemplo: que, eventualmente, ocorre-me que tanto 21e 56são múltiplos de 7e assim certamente 2156 = 21 x 100 + 56também é um múltiplo de 7.

Sua tarefa é escrever um código que identifique números mais fáceis de fatorar devido a uma coincidência desse tipo.

Mais precisamente:

Escreva um programa ou função que use um número inteiro positivo ncomo entrada e retorne um valor verdadeiro se existir um divisor d(maior que 1) que npossa ser dividido em dois para gerar dois números inteiros positivos, cada um dos quais é múltiplo d; retorne um valor falso se não.

  • "Dividido em dois" significa o que você pensa: a representação usual da base 10 nparticionada em algum momento em uma metade da frente e uma metade traseira para produzir dois outros números inteiros da base 10. Tudo bem se o segundo inteiro tem um zero à esquerda (mas nota que ele deve ser um inteiro positivo, então a divisão 1230em 123e 0não é válido).
  • Os valores de verdade e falsidade podem depender da entrada. Por exemplo, se qualquer número inteiro diferente de zero é verdadeiro no seu idioma de escolha, você pode devolver o divisor dou uma das "partes" de n(ou nela mesma nesse caso).
  • Por exemplo, qualquer número par com pelo menos dois dígitos no conjunto {2, 4, 6, 8}produzirá um valor verdadeiro: basta dividi-lo após o primeiro dígito par. Também, por exemplo, qualquer número primo nproduzirá um valor falso, assim como qualquer número de um dígito.
  • Observe que basta considerar os divisores principais d.
  • Você pode assumir que a entrada é válida (ou seja, um número inteiro positivo).

Isso é , então o código mais curto em bytes vence. Porém, soluções em todos os idiomas são bem-vindas, para que possamos buscar o código mais curto em cada idioma, não apenas o código mais curto em geral.

Casos de teste

(Você só precisa emitir um valor verdadeiro ou falso; as anotações abaixo são apenas uma explicação). Algumas entradas que produzem valores verdadeiros são:

39  (3 divides both 3 and 9)
64  (2 divides both 6 and 4)
497  (7 divides both 49 and 7)
990  (splitting into 99 and 0 is invalid; but 9 divides both 9 and 90)
2233  (11 divides both 22 and 33)
9156  (3 divides both 9 and 156; or, 7 divides both 91 and 56)
11791  (13 divides both 117 and 91)
91015  (5 divides both 910 and 15)
1912496621  (23 divides both 1912496 and 621; some splittings are multiples of 7 as well)
9372679892  (2473 divides both 937267 and 9892; some splittings are multiples of 2 as well)

Algumas entradas que geram valores falsos são:

52
61
130  (note that 13 and 0 is not a valid splitting)
691
899
2397
9029
26315
77300  (neither 7730 and 0 nor 773 and 00 are valid splittings)
2242593803

¹ sim, eu realmente faço isso

Respostas:


7

Retina , 31 29 bytes


,$';$`
\d+
$*
;(11+)\1*,\1+;

Experimente online!

Emite um número inteiro positivo para entradas válidas e zero para entradas inválidas.

Eu não recomendaria esperar pelos casos de teste maiores ...

Explicação


,$';$`

Em cada posição da entrada, insira uma vírgula, tudo antes dessa posição, depois um ponto-e-vírgula e tudo depois dessa posição. O que isso faz? Ele nos fornece todas as divisões possíveis de um número (dividido por ,, separado por ;) e, em seguida, a entrada novamente no final. Então a entrada 123se torna

,123;1,23;12,3;123,;123
     ^     ^     ^

onde marquei os caracteres de entrada originais (o que não está marcado é o que inserimos). Observe que isso cria splitters inválidos que não são reais e também não se importa se o componente à direita é todos os zeros, mas evitaremos aceitá-los posteriormente. O benefício de criar divisões inválidas é que sabemos que cada divisão válida tem um ;na frente e depois dela, para que possamos salvar dois bytes nos limites da palavra.

\d+
$*

Converta cada número em unário.

;(11+)\1*,\1+;

Combine uma divisão, combinando as duas metades como múltiplos de algum número que seja pelo menos 2.


Pergunta rápida sobre Retina: O que a nova linha líder faz?
HyperNeutrino 24/03

@HyperNeutrino Bem, a primeira linha é o primeiro regex que correspondemos e queremos corresponder ao regex vazio, para inserir a substituição em todas as posições entre os caracteres.
Martin Ender

Ah, tudo bem. Obrigado! Eu provavelmente deveria olhar um pouco mais a Retina; como parece amplamente baseado em regex, pode ser bom para problemas de complexidade de kolmogorov .
HyperNeutrino

Poderia ser a última linha;(11+)+,\1+;
Riley

@Riley que não garante que o primeiro segmento seja múltiplo do mesmo fator.
Martin Ender

6

Braquilog (2), 8 bytes

~c₂ḋᵐ∋ᵐ=

Experimente online!

Explicação

~c₂ḋᵐ∋ᵐ=
~c₂       Split the input into two pieces
    ᵐ ᵐ   On each of those pieces:
   ḋ ∋      Choose a prime factor
       =  such that both the chosen factors are equal

Claramente, se o mesmo número (maior que 1) dividir as duas partes, o mesmo número primo dividirá as duas. Exigir que o fator seja primo desaprova ordenadamente 1 como um fator. Também impede que um literal 0seja escolhido como um segmento de um número (porque 0não possui fatoração primária e causará falha).

Não há necessidade de verificar se há zeros internos correspondentes; se uma divisão de xe 0yé válido, x0e yvai funcionar tão bem (e indo para o outro lado, se x0e yobras, então temos uma solução de trabalho, independentemente de xe 0yiria funcionar ou não).

Um programa completo do Brachylog, como este, retorna um booleano; true.se houver alguma maneira de executá-lo sem falha (por exemplo, para fazer escolhas que não ocorram erros), false.se todos os caminhos levarem à falha. É exatamente o que queremos aqui.


4

Geléia , 14 12 11 10 bytes

ŒṖḌo1g/€P>

Graças a @ JonathanAllan por jogar fora um byte!

Experimente online!

Como funciona

ŒṖḌo1g/€P>  Main link. Argument: n

ŒṖ          Compute all partitions of n's decimal digits.
  Ḍ         Undecimal; convert each array in each partition back to integer.
   o1       OR 1; replace disallowed zeroes with ones.
     g/€    Reduce (/) each (€) partition by GCD (g).
            The last GCD corresponds to the singleton partition and will always be
            equal to n. For a falsy input, all other GCDs will be 1.
        P   Take the product of all GCDs.
         >  Compare the product with n.

Eu acho que você pode largar o D, como make_digitsestá em vigor para ŒṖ.
Jonathan Allan

Por alguma razão, presumi que isso criaria um intervalo ... Obrigado!
Dennis

3

Mathematica, 63 62 bytes

(1 byte graças a Greg Martin)

1<Max@@GCD@@@Table[1~Max~#&/@Floor@{Mod[#,t=10^n],#/t},{n,#}]&

É uma função que recebe um número inteiro como entrada e retorna True ou False. Se você testá-lo em um número grande, leve um livro para ler enquanto espera.

Explicação:

  • Floor@{Mod[#,t=10^n],#/t}divide aritmeticamente a entrada nos seus últimos ndígitos e nos m-ndígitos restantes (ondem é o número total de dígitos).
  • Table[1~Max~#&/@...,{n,#}]faz isso para todos nos números de entrada. (Isso é muito grande. Só precisamos fazer isso até o número de dígitos da entrada, mas dessa maneira economiza bytes e ainda dá o resultado correto.) O 1~Max~#&/@bit se livra de zeros, portanto, números como 130 -> {13,0}não contam como True.
  • 1<Max@@GCD@@@... encontra o maior divisor comum de cada um desses pares e verifica se algum desses divisores é maior que 1. Se forem, encontramos uma maneira de fatorar o número dividindo-o.

1
Boa resposta! Você pode salvar um byte com {#~Mod~10^n,#/10^n}ou {Mod[#,t=10^n],#/t}.
Greg Martin

Eu tentei #~Mod~10^n, mas parece que está entre colchetes em Mod[#,10]^nvez de Mod[#,10^n]. Mas não pensei na sua segunda sugestão!
Não é uma árvore

ponto justo sobreMod[#,10]^n
Greg Martin


2

C, 145 142 139 138 135 bytes

i,a,b;f(){char s[99];scanf("%s",s);for(char*p=s;*p++;)for(b=atoi(p),i=*p,*p=0,a=atoi(s),*p=i,i=1;i++<b;)*s=a%i-b%i|b%i?*s:0;return!*s;}

2

JavaScript (ES6), 74 71 70 bytes

f=(s,t='',u)=>u?s%t?f(t,s%t,1):t:s&&f(t+=s[0],s=s.slice(1),1)>1|f(s,t)
<input oninput=o.textContent=f(this.value)><span id=o>

Recebe a entrada como uma sequência, o que é útil para o snippet. Editar: salvou 3 bytes graças a @ user81655.


Salva dois bytes: (c,i)-> c, i+1-> ++i, t=''-> i=t='', este truque é útil a qualquer momento você precisa usar índices baseados-1 e ter um lugar para inicializar ia 0.
user81655

Também acredito que t=''poderia ser t=0, já que adicionar ccoerção a uma string de qualquer maneira.
user81655

@ user81655 Isso aconteceu porque eu originalmente fatiei de e para i, então não precisava de índices baseados em 1, mas depois joguei a primeira fatia no t+=c.
Neil

Ah ok. Também uma última coisa, eu acho que isso também poderia ser mais curto em função recursiva: f=(x,y,z)=>z?x%y?g(y,x%y):y:x?f(x,y,1)>1||f(x.slice(1),~~y+x[0]):0. Combinei sua função GCD ftambém. Provavelmente poderia ser jogado ainda mais. Última sugestão, eu prometo! : P
user81655

@ user81655 Infelizmente, minha gcdfunção simplificada demais não funciona quando x=0, e, contornando isso, seu erro de digitação me levou a 72 bytes, por isso, foi uma sorte que eu fosse capaz de desviar 2 bytes.
Neil

2

Python 3, 133 118 117 bytes

i,j=int,input()
from fractions import*
print(any(i(j[k:])*i(j[:k])*~-gcd(i(j[k:]),i(j[:k]))for k in range(1,len(j))))

Certamente não é o mais curto, provavelmente poderia ser reduzido um pouco. Funciona a O(n)tempo. A entrada é \d+recebida no formato e a saída é fornecida no formato (True|False)como valor booleano padrão do Python
-3 bytes, graças ao Dead Possum
-15 bytes, graças ao ovs
-1 byte, graças a Esse cara


from fractions import*salvaria 3 bytes
Dead Possum

Retorna True para 900. Acho que está errado. Mb você deve mudar interior anypara all? Se for esse o caso, você pode alterar toda essa parte para i(j[k:])and i(j[:k])elevar tudo para 125 bytes. Aqui estão as correções #
Dead Possum

Você pode substituir any(i(j[k:])*i(j[:k])*~-gcd(i(j[k:]),i(j[:k]))for k in range(1,len(j)))
oe

@DeadPossum Ah, certo, eu deveria ter feito isso. E sim, meu método atual tem muitas partes jogáveis, mas vou seguir as sugestões de ovs. Obrigado por apontar isso! (realmente deve testei me ... oh bem ...)
HyperNeutrino

Você pode remover um byte (quase nada) por remover o espaço em branco entre)) for
caird coinheringaahing

1

QBIC , 91 90 bytes

;_LA|[a-1|B=left$(A,b)┘C=right$(A,a-b)┘x=!B!┘y=!C![2,x|~(x>1)*(y>1)*(x%c=0)*(y%c=0)|_Xq}?0

Explicação:

;               Get A$ from the command prompt
_LA|            Get the length of A$ and place it in a% (num var)
[a-1|           for b%=1; b% <= a%-1; b%++
B=left$(A,b)    break A$ in two components on index b%
C=right$(A,a-b)
x=!B!┘y=!C!     Convert both parts from string to num, assign to x% and y%
[2,x|           FOR c% = 2; c% <= x%; c%++

This next IF (~ in QBIC) is a bit ... iffy. It consists of a set of comparators.
Each comparator yields a -1 or a 0. We take the product of these. At any failed
comparison this will yield 0. When successful, it yields 1, which is seen as true by QBasic.

~(x>1)*(y>1)        IF X>1 and Y>1 --> this stops '00' and '1' splits.
*(x%c=0)*(y%c=0)    Trial divide the splits on loop counter c%.

|_Xq            Success? THEN END, and PRINT q (which is set to 1 in QBIC)
}               Close all language constructs (2 FOR loops and an IF)
?0              We didn't quit on match, so print 0


1

Perl 5 , 46 bytes

43 bytes de código + 3 bytes para -psinalizador.

s~~$\|=grep!($`%$_|$'%$_),2..$`if$`*$'~ge}{

Experimente online! ou tente esta versão modificada, permitindo várias entradas.
Você provavelmente não deseja tentar isso com a maior entrada, pois pode levar um tempo (muito longo).

Explicações:
Nós iteramos através de cada posição na palavra com s~~~g, $`contendo os números antes e $'depois. Se $`*$'for verdadeiro (significa que nenhum está vazio e nenhum está 0), então verificamos se um número entre 2 e $`divide os dois (com o grep!(...),2..$`). Nesse caso, $\|=..será definido $\como um valor diferente de zero, que é implicitamente impresso no final graças ao -psinalizador.


2
Se alguém souber como renderizar uma $<backquote>remarcação no SE, ficaria grato se você me disser como.
Dada

1
Você pode fazer isso usando explícito <code></code>(em vez de ``) e depois escapando das aspas como \`. Além disso, esse comentário foi difícil de escrever, porque precisa ser de escape duplo (e os dois conjuntos de regras de escape são diferentes!).

@ ais523 Maravilhoso, muito obrigado! :)
Dada

0

Python 2 , 69 bytes

f=lambda n,d=10,k=2:k<d<n and(n/d%k+n%d%k<1<n%d)|f(n,d,k+1)|f(n,10*d)

Usa recursão em vez de incorporados ao GCD.

Experimente online!

Como funciona

Quando f é chamado com um a três argumentos ( d assume o padrão de 10 , k a 2 ), ele primeiro verifica o valor da expressão k<d<n. Se as desigualdades k <d e d <n forem mantidas, a expressão a seguir andserá executada e seu valor será retornado; caso contrário, f retornará False .

No primeiro caso, começamos avaliando a expressão n/d%k+n%d%k<1<n%d.

d sempre será uma potência de dez, portanto, n/de n%defetivamente divida os dígitos decimais em n em duas fatias. Essas fatias são divisíveis por k se e somente se forem n/d%k+n%d%kavaliadas como 0 , o que é testado comparando o resultado com 1 .

Como parte dos requisitos é que ambas as fatias devem representar números inteiros positivos, o valor de n%dtambém é comparado com 1 . Observe que 1 não possui divisores principais, portanto, a comparação mais cara com 0 não é necessária. Além disso, observe que d <n já garante quen/d será avaliado como um número inteiro positivo.

Finalmente, recursivamente tudo f(n,d,k+1)(tentando o próximo divisor comum em potencial) e f(n,10*d)(tentando a divisão) e retorna o OR lógico dos três resultados. Este meio f retornará verdadeiro se (e somente se) k é um divisor comum de n / d e n d% ou o mesmo é verdadeiro para um valor maior de k e / ou uma maior potência de dez d .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.