# Titel: Verallgemeinerter Chinesischer Restsatz
# Autor: Manuel Stuebler
# einfacher euklidscher Algorithmus
def euklid(a, b):
while b != 0:
a, b = b, a % b
return a
# induktiver, erweiterter euklidscher Algorithmus
# liefert zus. die Faktoren x, y der Linearkombination
def erwEuklid(a, b):
# Hilfsvariablen
u, s, v, t = 1, 0, 0, 1
while b != 0:
q = a//b # Quotient q
u, s, v, t = s, u-q*s, t, v-q*t
a, b = b, a % b # Rest r
return a, u, v
# das Inverse von a bez. b mit dem erweiterten
# euklidschen Algorithmus berechnen
def inverse(a,b):
(c, x, y) = erwEuklid(a, b)
return x
# den verallgemeinerten chinesischen Restsatz anwenden
def vcrs(c):
k = len(c) # Anzahl der Kongruenzen
#print("k = " + str(k))
# initialer Wert entspricht der ersten Kongruenz a_0 mod m_0
a, M = c[0]
#print("a, M = " + str((a, M)))
# c[i][0] -> a_i , c[i][1] -> m_i
# fuer jede weitere Kongruenz iterativ ein mit der bisher
# gefundenen Loesung vertraegliches Ergebnis berechnen
for i in range(1, k):
# j = Differenz aus aktuellem a_i und vorangegangem
# Ergebnis a mod M der bisher betrachteten Kongruenzen 0..i
j = c[i][0] - a
#print("c (" + str(i) + ") = " + str(j))
(d, x, y) = erwEuklid(M, c[i][1])
#print(str(d) + " = " + str(x) + "*" + str(M) +
# " + " + str(y) + "*" + str(c[i][1]))
# d muss j teilen, damit sich die neue Kongruenz
# in das bisher gefundene Ergebnis a mod M einreiht
if ((j % d) != 0):
print("Es existiert keine Loesung.")
return (-1,-1)
Mt = M # temporaer Zwischenspeichern fuer a = ...
M = c[i][1]*M//d # neuen Modul M berechnen
a = (a + Mt*j*x//d) % M # neues a mod M berechnen
return (a % M, M) # Ergebnis a mod M zurueckgeben
# Eingabe und Ausgabe
def main():
l = [] # Tripel in diese Liste einlesen
while True:
try:
s = input()
if (len(s) < 5):
continue
b = tuple(s.split())
a = (int(b[0]), int(b[1]), int(b[2]))
l.append(a)
except:
break
# durch Kuerzen bzw. Multiplikation mit dem jeweils Inversen
# wird der Vorfaktor a eliminiert -> x = b_neu mod m_neu
c = []
for t in l:
g = euklid(t[0], t[2])
# der ggT ist != 1 -> Kuerzen der Kongruenz (a_neu=1,b_neu=b/a)
# dabei muss der Modul um den ggT reduziert werden (m_neu=m/ggT)
if (g != 1):
if ((t[0] == g) and (t[1] % g) == 0):
c.append((t[1]//t[0], t[2]//g))
else:
print("Es existiert keine Loesung.")
# ist der ggT = 1 so kann das Inverse bestimmt werden
# und mit a, sowie b multipliziert werden (a_neu=1,b_neu=a*inv(a))
else:
i = inverse(t[0], t[2])
i = i % t[2]
c.append((t[1]*i,t[2]))
# loesen des Systems von Kongruenzen
ret = vcrs(c)
if (ret != (-1,-1)):
# und entsprechend formatiert ausgeben
print(str(ret[0]) + " " + str(ret[1]))
if __name__ == "__main__":
main()
IyBUaXRlbDogVmVyYWxsZ2VtZWluZXJ0ZXIgQ2hpbmVzaXNjaGVyIFJlc3RzYXR6CiMgQXV0b3I6IE1hbnVlbCBTdHVlYmxlcgoKIyBlaW5mYWNoZXIgZXVrbGlkc2NoZXIgQWxnb3JpdGhtdXMKZGVmIGV1a2xpZChhLCBiKToKICAgIHdoaWxlIGIgIT0gMDoKICAgICAgICBhLCBiID0gYiwgYSAlIGIKICAgIHJldHVybiBhCgojIGluZHVrdGl2ZXIsIGVyd2VpdGVydGVyIGV1a2xpZHNjaGVyIEFsZ29yaXRobXVzCiMgbGllZmVydCB6dXMuIGRpZSBGYWt0b3JlbiB4LCB5IGRlciBMaW5lYXJrb21iaW5hdGlvbgpkZWYgZXJ3RXVrbGlkKGEsIGIpOgogICAgIyBIaWxmc3ZhcmlhYmxlbgogICAgdSwgcywgdiwgdCA9IDEsIDAsIDAsIDEKICAgIHdoaWxlIGIgIT0gMDoKICAgICAgICBxID0gYS8vYiAjIFF1b3RpZW50IHEKICAgICAgICB1LCBzLCB2LCB0ID0gcywgdS1xKnMsIHQsIHYtcSp0CiAgICAgICAgYSwgYiA9IGIsIGEgJSBiICMgUmVzdCByCiAgICByZXR1cm4gYSwgdSwgdgoKIyBkYXMgSW52ZXJzZSB2b24gYSBiZXouIGIgbWl0IGRlbSBlcndlaXRlcnRlbgojIGV1a2xpZHNjaGVuIEFsZ29yaXRobXVzIGJlcmVjaG5lbgpkZWYgaW52ZXJzZShhLGIpOgogICAgKGMsIHgsIHkpID0gZXJ3RXVrbGlkKGEsIGIpCiAgICByZXR1cm4geAoKIyBkZW4gdmVyYWxsZ2VtZWluZXJ0ZW4gY2hpbmVzaXNjaGVuIFJlc3RzYXR6IGFud2VuZGVuCmRlZiB2Y3JzKGMpOgogICAgayA9IGxlbihjKSAjIEFuemFobCBkZXIgS29uZ3J1ZW56ZW4KICAgICNwcmludCgiayA9ICIgKyBzdHIoaykpCgogICAgIyBpbml0aWFsZXIgV2VydCBlbnRzcHJpY2h0IGRlciBlcnN0ZW4gS29uZ3J1ZW56IGFfMCBtb2QgbV8wCiAgICBhLCBNID0gY1swXQogICAgI3ByaW50KCJhLCBNID0gIiArIHN0cigoYSwgTSkpKQoKICAgICMgY1tpXVswXSAtPiBhX2kgLCBjW2ldWzFdIC0+IG1faQogICAgIyBmdWVyIGplZGUgd2VpdGVyZSBLb25ncnVlbnogaXRlcmF0aXYgZWluIG1pdCBkZXIgYmlzaGVyCiAgICAjIGdlZnVuZGVuZW4gTG9lc3VuZyB2ZXJ0cmFlZ2xpY2hlcyBFcmdlYm5pcyBiZXJlY2huZW4KICAgIGZvciBpIGluIHJhbmdlKDEsIGspOgogICAgICAgICMgaiA9IERpZmZlcmVueiBhdXMgYWt0dWVsbGVtIGFfaSB1bmQgdm9yYW5nZWdhbmdlbQogICAgICAgICMgRXJnZWJuaXMgYSBtb2QgTSBkZXIgYmlzaGVyIGJldHJhY2h0ZXRlbiBLb25ncnVlbnplbiAwLi5pCiAgICAgICAgaiA9IGNbaV1bMF0gLSBhCiAgICAgICAgI3ByaW50KCJjICgiICsgc3RyKGkpICsgIikgPSAiICsgc3RyKGopKQoKICAgICAgICAoZCwgeCwgeSkgPSBlcndFdWtsaWQoTSwgY1tpXVsxXSkKICAgICAgICAjcHJpbnQoc3RyKGQpICsgIiA9ICIgKyBzdHIoeCkgKyAiKiIgKyBzdHIoTSkgKwogICAgICAgICMgICAgICAiICsgIiArIHN0cih5KSArICIqIiArIHN0cihjW2ldWzFdKSkKCiAgICAgICAgIyBkIG11c3MgaiB0ZWlsZW4sIGRhbWl0IHNpY2ggZGllIG5ldWUgS29uZ3J1ZW56CiAgICAgICAgIyBpbiBkYXMgYmlzaGVyIGdlZnVuZGVuZSBFcmdlYm5pcyBhIG1vZCBNIGVpbnJlaWh0CiAgICAgICAgaWYgKChqICUgZCkgIT0gMCk6CiAgICAgICAgICAgcHJpbnQoIkVzIGV4aXN0aWVydCBrZWluZSBMb2VzdW5nLiIpCiAgICAgICAgICAgcmV0dXJuICgtMSwtMSkKCiAgICAgICAgTXQgPSBNICMgdGVtcG9yYWVyIFp3aXNjaGVuc3BlaWNoZXJuIGZ1ZXIgYSA9IC4uLgogICAgICAgIE0gPSBjW2ldWzFdKk0vL2QgIyBuZXVlbiBNb2R1bCBNIGJlcmVjaG5lbgogICAgICAgIGEgPSAoYSArIE10KmoqeC8vZCkgJSBNICMgbmV1ZXMgYSBtb2QgTSBiZXJlY2huZW4KCiAgICByZXR1cm4gKGEgJSBNLCBNKSAjIEVyZ2VibmlzIGEgbW9kIE0genVydWVja2dlYmVuCgoKIyBFaW5nYWJlIHVuZCBBdXNnYWJlCmRlZiBtYWluKCk6CgogICAgbCA9IFtdICMgVHJpcGVsIGluIGRpZXNlIExpc3RlIGVpbmxlc2VuCgogICAgd2hpbGUgVHJ1ZToKICAgICAgICB0cnk6CiAgICAgICAgICAgIHMgPSBpbnB1dCgpCiAgICAgICAgICAgIGlmIChsZW4ocykgPCA1KToKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIGIgPSB0dXBsZShzLnNwbGl0KCkpCiAgICAgICAgICAgIGEgPSAoaW50KGJbMF0pLCBpbnQoYlsxXSksIGludChiWzJdKSkKICAgICAgICAgICAgbC5hcHBlbmQoYSkKICAgICAgICBleGNlcHQ6CiAgICAgICAgICAgIGJyZWFrCgogICAgIyBkdXJjaCBLdWVyemVuIGJ6dy4gTXVsdGlwbGlrYXRpb24gbWl0IGRlbSBqZXdlaWxzIEludmVyc2VuCiAgICAjIHdpcmQgZGVyIFZvcmZha3RvciBhIGVsaW1pbmllcnQgLT4geCA9IGJfbmV1IG1vZCBtX25ldQogICAgYyA9IFtdCgogICAgZm9yIHQgaW4gbDoKICAgICAgICBnID0gZXVrbGlkKHRbMF0sIHRbMl0pCgogICAgICAgICMgZGVyIGdnVCBpc3QgIT0gMSAtPiBLdWVyemVuIGRlciBLb25ncnVlbnogKGFfbmV1PTEsYl9uZXU9Yi9hKQogICAgICAgICMgZGFiZWkgbXVzcyBkZXIgTW9kdWwgdW0gZGVuIGdnVCByZWR1emllcnQgd2VyZGVuIChtX25ldT1tL2dnVCkKICAgICAgICBpZiAoZyAhPSAxKToKICAgICAgICAgICAgaWYgKCh0WzBdID09IGcpIGFuZCAodFsxXSAlIGcpID09IDApOgogICAgICAgICAgICAgICAgYy5hcHBlbmQoKHRbMV0vL3RbMF0sIHRbMl0vL2cpKQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgcHJpbnQoIkVzIGV4aXN0aWVydCBrZWluZSBMb2VzdW5nLiIpCiAgICAgICAgIyBpc3QgZGVyIGdnVCA9IDEgc28ga2FubiBkYXMgSW52ZXJzZSBiZXN0aW1tdCB3ZXJkZW4KICAgICAgICAjIHVuZCBtaXQgYSwgc293aWUgYiBtdWx0aXBsaXppZXJ0IHdlcmRlbiAoYV9uZXU9MSxiX25ldT1hKmludihhKSkKICAgICAgICBlbHNlOgogICAgICAgICAgICBpID0gaW52ZXJzZSh0WzBdLCB0WzJdKQogICAgICAgICAgICBpID0gaSAlIHRbMl0KICAgICAgICAgICAgYy5hcHBlbmQoKHRbMV0qaSx0WzJdKSkKCiAgICAjIGxvZXNlbiBkZXMgU3lzdGVtcyB2b24gS29uZ3J1ZW56ZW4KICAgIHJldCA9IHZjcnMoYykKCiAgICBpZiAocmV0ICE9ICgtMSwtMSkpOgogICAgICAgICMgdW5kIGVudHNwcmVjaGVuZCBmb3JtYXRpZXJ0IGF1c2dlYmVuCiAgICAgICAgcHJpbnQoc3RyKHJldFswXSkgKyAiICIgKyBzdHIocmV0WzFdKSkKCgppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogIG1haW4oKQo=