Teorema do Restante Chinês

21

o Teorema Chinês do Restante nos diz que sempre podemos encontrar um número que produz quaisquer restos necessários sob diferentes módulos primos. Seu objetivo é escrever código para gerar esse número em tempo polinomial. O menor código vence.

Por exemplo, digamos que recebemos essas restrições ( %representa mod):

n % 7  == 2
n % 5  == 4
n % 11 == 0

Uma solução é n=44. A primeira restrição é satisfeita porque 44 = 6*7 + 2, e assim 44tem o restante 2quando dividido por 7, e assim 44 % 7 == 2. As outras duas restrições também são atendidas. Existem outras soluções, como n=814e n=-341.

Entrada

Uma lista não vazia de pares (p_i,a_i), em que cada módulo p_ié um primo distinto e cada destino a_ié um número natural no intervalo 0 <= a_i < p_i. Você pode receber informações da forma que for mais conveniente; não precisa ser realmente uma lista de pares. Você não pode assumir que a entrada está classificada.

Saída

Um número inteiro ntal que n % p_i == a_ipara cada índice i. Ele não precisa ser o menor valor possível e pode ser negativo.

Restrição de tempo polinomial

Para evitar soluções baratas que apenas tentar n=0, n=1, n=2, e assim por diante, seu código deve ser executado em tempo polinomial no comprimento da entrada . Observe que um número mna entrada possui comprimento Θ(log m); portanto, mele não é polinomial em seu comprimento. Isso significa que você não pode contar até mou executar um mtempo de operação , mas pode calcular operações aritméticas nos valores.

Você não pode usar um formato de entrada ineficiente como unário para contornar isso.

Outras proibições

Não são permitidos embutidos para fazer o seguinte: Implemente o teorema chinês Remainder, resolva equações ou números de fatores.

Você pode usar built-ins para encontrar mods e fazer adição, subtração, multiplicação e exponenciação modulares (com expoente de número natural). Você não pode usar outras operações modulares integradas, incluindo inversa modular, divisão e busca de pedidos.

Casos de teste

Estes fornecem a menor solução não negativa. Sua resposta pode ser diferente. Provavelmente é melhor se você verificar diretamente se sua saída satisfaz cada restrição.

[(5, 3)] 
3

[(7, 2), (5, 4), (11, 0)]
44

[(5, 1), (73, 4), (59, 30), (701, 53), (139, 112)]
1770977011

[(982451653, 778102454), (452930477, 133039003)]
68121500720666070
xnor
fonte
Por que nenhuma divisão?
jimmy23013
@ user23013 Nenhuma divisão modular, pois é basicamente inversa modular.
Xnor 22/03
A inversão de matrizes conta como solução de equações?
flawr
@ flawr: Eu acho que sim.
Alex A.
@ xnor: O que você acha? E as funções de otimização?
flawr

Respostas:

9

Mathematica, 55 51 45

O inverso modular é proibido, mas a exponenciação modular é permitida. Pelo pequeno teorema de Fermat n^(-1) % p == n^(p-2) % p,.

(PowerMod[x=1##&@@#/#,#-2,#]x).#2&@@Thread@#&

Exemplo:

In[1]:= f = (PowerMod[x=1##&@@#/#,#-2,#]x).#2&@@Thread@#&;

In[2]:= f[{{5, 3}}]

Out[2]= 3

In[3]:= f[{{7, 2}, {5, 4}, {11, 0}}]

Out[3]= 1584

In[4]:= f[{{5, 1}, {73, 4}, {59, 30}, {701, 53}, {139, 112}}]

Out[4]= 142360350966

Apenas por diversão:

ChineseRemainder@@Reverse@Thread@#&
alefalpha
fonte
11
Você pode salvar um byte trocando a ordem dos argumentos da função mais interna, para que você possa usar PowerMod[#2,#-2,#]e também não acho que exista um requisito para que a função seja nomeada, reduzindo-a para 48.
Martin Ender
Sim, funções sem nome estão OK.
Xnor 22/03
6

Python 2, 165 101 99 98 85 bytes

Usando o pequeno teorema de Fermat como as outras respostas. Não se preocupa em manter a soma final dentro da faixa modular, pois não estamos interessados ​​na menor solução. Obrigado Volatility por salvar 13 bytes.

l=input();x=reduce(lambda a,b:a*b[0],l,1)
print sum(x/a*b*pow(x/a,a-2,a)for a,b in l)

[(5, 3)]
3
[(7, 2), (5, 4), (11, 0)]
1584
[(5, 1), (73, 4), (59, 30), (701, 53), (139, 112)]
142360350966
Uri Granta
fonte
11
Você pode remover o espaço antes for.
Isaacg
11
x/a*b*pow(x/a,a-2,a)for a,b in lDeveria trabalhar.
Volatilidade
Excelente ponto! Eu estava tentando me livrar da redundância óbvia lá, mas esqueci que eu poderia apenas desfazer as malas.
Uri Granta 23/03
4

Pitão, 40 37 36 29

M*G.^G-H2Hsm*edg/u*GhHQ1hdhdQ

Usa o pequeno teorema de Fermat, graças aos alefalpha. Calcula usando esta fórmula .

orlp
fonte
3

Ruby, 129

Bem, camaradas, parece que as soluções Ruby precisam ser mais longas porque a exponenciação modular não está disponível sem carregar a biblioteca openssl e fazer conversões no OpenSSL :: BN. Ainda assim, me diverti escrevendo:

require("openssl")
z=eval(gets)
x=1
z.map{|a,b|x*=a}
s=0
z.map{|a,b|e=a.to_bn;s+=(x/a).to_bn.mod_exp(e-2,e).to_i*b*x/a}
puts(s)
Atsby
fonte
Você não precisa os parênteses ao chamar require, evalou puts.
Tutleman 27/07
2

Python 2, 61

n=P=1
for p,a in input():n+=P*(a-n)*pow(P,p-2,p);P*=p
print n

Isso emprega uma variação da construção do produto que outras respostas usam.

A idéia é fazer um loop sobre as restrições e atualizar a solução npara atender à restrição atual sem atrapalhar as anteriores. Para fazer isso, rastreamos o produto Pdos primos vistos até agora e observamos que a adição de um múltiplo de Pnão tem efeito modulo a qualquer primo já visto.

Portanto, precisamos mudar npara satisfazer n%p == aadicionando o múltiplo certo de P. Resolvemos o coeficiente c:

(n + P*c) % p == a

Isso requer que c = (a-n) * P^(-1), onde o inverso é tomado módulo p. Como outros observam, o inverso pode ser calculado pelo Pequeno Teorema de Fermat como P^(-1) = pow(P,p-2,p). Então,, c = (a-n) * pow(P,p-2,p)e nós atualizamos npor n+= P * (a-n) * pow(P,p-2,p).

xnor
fonte
1

Haskell, 68 100 bytes

f l=sum[p#(m-2)*n*p|(m,n)<-l,let a#0=1;a#n=(a#div n 2)^2*a^mod n 2`mod`m;p=product(map fst l)`div`m]

Uso: f [(5,1), (73,4), (59,30), (701,53), (139,112)]->142360350966 .

Edit: agora com uma função rápida "power / mod". Versão antiga (68 bytes) com função de energia embutida:

f l=sum[l#m^(m-2)`mod`m*n*l#m|(m,n)<-l]
l#m=product(map fst l)`div`m
nimi
fonte
Eu suspeito que sua implementação do power-mod não é polinomial, uma vez que o expoente produz um número enorme antes do mod. Você já tentou o último caso de teste?
xnor
@ xnor: o último caso de teste fica sem memória após alguns segundos na minha máquina de 2 GB. Eu adicionei uma função power / mod rápida.
nimi