Pitão, 92 bytes
I!%vzhK%2u?sm,ed-hd*ed/F<G2cG2@G1G+~Q,hQ_eQj9 2)J*L/vzhKtKeoSNm-VJ/RhK_*LdQsm+LdtM3/V*LhK_JQ
É um monstro e tanto.
Experimente online: Demonstração . O formato de entrada é c\n[a,b]
e o formato de saída é [x,y]
.
Caso não exista uma solução inteira, não imprimirei nada e, caso não exista uma solução natural natural, simplesmente imprimirei uma solução inteira aleatória.
Explicação (Visão Geral Bruta)
Inicialmente, encontrarei uma solução inteira para a equação ax + by = gcd(a,b)
usando o algoritmo Euclidiano Estendido.
Então eu modificarei a solução (minha multiplicação a
e b
com c/gcd(a,b)
) para obter uma solução inteira de ax + by = c
. Isso funciona, se c/gcd(a,b)
é um número inteiro. Caso contrário, não existe uma solução.
Todas as outras soluções inteiras têm o formato a(x+n*b/d) + b(y-n*a/d) = c
com d = gcd(a,b)
for inteiro n
. Usando as duas desigualdades x+n*b/d >= 0
e y-n*a/d >= 0
eu posso determinar 6 valores possíveis para n
. Vou tentar todos os 6 deles e imprimir a solução com o maior coeficiente mais baixo.
Explicação (detalhada)
O primeiro passo é encontrar uma solução inteira para a equação ax' + by' = gcd(a,b)
. Isso pode ser feito usando o algoritmo euclidiano estendido. Você pode ter uma idéia de como isso funciona na Wikipedia . A única diferença é que, em vez de usar 3 colunas ( r_i s_i t_i
), usarei 6 colunas ( r_i-1 r_i s_i-1 s_i t_i-1 t_i
). Dessa forma, não preciso manter as duas últimas linhas na memória, apenas a última.
K%2u?sm,ed-hd*ed/F<G2cG2@G1G+~Q,hQ_eQj9 2) implicit: Q = [a,b] (from input)
j9 2 convert 9 to base 2: [1,0,0,1]
+ Q add to Q => [a,b,1,0,0,1]
this is the initial row
u ) start with G = ^ and update G repeatedly
by the following expression, until
the value of G doesn't change anymore
? @G1 if G[1] != 0:
cG2 split G into parts of 2
m map the parts d to:
, the pair
ed d[1]
-hd*ed/F<G2 d[0]-d[1]*G[0]/G[1]
s unfold
else:
G G (don't change it, stop criterion for u)
%2 take every second element
we get the list [gcd(a,b),x',y']
K store this list in K
~Q,hQ_eQ afterwards change Q to [Q[0],-Q[1]] = [a,-b]
This will be important for the other parts.
Agora eu quero encontrar uma solução para ax + by = c
. Isso é possível apenas quando c mod gcd(a,b) == 0
. Se esta equação for satisfeita, eu simplesmente multiplico x',y'
com c/gcd(a,b)
.
I!%vzhK...J*L/vzhKtK implicit: z = c in string format (from input)
%vzhK evaluated(z) mod K[0] (=gcd(a,b))
I! if not ^ than:
/vzhK c/K[0]
*L tK multipy ^ to each element in K[1:] (=[x',y'])
J and store the result in J, this is now [x,y]
Temos uma solução inteira para ax + by = c
. Aviso, que x
, y
ou ambos, podem ser negativo. Portanto, nosso objetivo é transformá-los em não negativos.
O bom das equações diofantinas é que podemos descrever todas as soluções usando apenas uma solução inicial. Se (x,y)
é uma solução, todas as outras soluções têm a forma (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
de n
número inteiro.
Portanto, queremos encontrar a n
, onde x-n*b/gcd(a,b) >= 0
e y+n*a/gcd(a,b >= 0
. Após alguma transformação, terminamos com as duas desigualdades n >= -x*gcd(a,b)/b
e n >= y*gcd(a,b)/a
. Observe que o símbolo de desigualdade pode olhar na outra direção devido à divisão com um potencial negativo a
ou b
. Não me importo muito com isso, simplesmente digo que um número de -x*gcd(a,b)/b - 1, -x*gcd(a,b)/b, -x*gcd(a,b)/b + 1
satisfaz definitivamente a desigualdade 1 e um número de y*gcd(a,b)/a - 1, y*gcd(a,b)/a, y*gcd(a,b)/a + 1
satisfaz a desigualdade 2. Existe um n
que satisfaz ambas as desigualdades, um dos 6 números também satisfaz.
Então eu calculo as novas soluções (x-n*b/gcd(a,b),y+n*a/gcd(a,b))
para todos os 6 valores possíveis de n
. E imprimo a solução com o menor valor mais alto.
eoSNm-VJ/RhK_*LdQsm+LdtM3/V*LhK_JQ
_J reverse J => [y,x]
*LhK multiply each value with K[0] => [y*gcd,x*gcd]
/V Q vectorized division => [y*gcd/a,-x*gcd/b]
m map each d of ^ to:
tM3 [-1,0,1]
+Ld add d to each ^
s unfold
these are the possible values for n
m map each d (actually n) of ^ to:
*LdQ multiply d to Q => [a*n,-b*n]
_ reverse => [-b*n,a*n]
/RhK divide by K[0] => [-b*n/gcd,a*n/gcd]
-VJ vectorized subtraction with J
=> [x+b*n/gcd,y-a*n/gcd]
oSN order the solutions by their sorted order
e print the last one
A classificação por ordem de classificação funciona da seguinte maneira. Estou usando o exemplo2x + 3y = 11
Classifico cada uma das 6 soluções (chamadas de chaves) e classifico as soluções originais por suas chaves:
solutions: [1, 3], [4, 1], [7, -1], [-5, 7], [-2, 5], [1, 3]
keys: [1, 3], [1, 4], [-1, 7], [-5, 7], [-2, 5], [1, 3]
sort by key:
solutions: [-5, 7], [-2, 5], [7, -1], [1, 3], [1, 3], [4, 1]
keys: [-5, 7], [-2, 5], [-1, 7], [1, 3], [1, 3], [1, 4]
Isso classifica uma solução completa não negativa até o fim (se houver).