import sys import ast import operator from fractions import gcd class Polynomial(): def __init__(self, lst, mod): super().__init__() self.poly = list(map(lambda x: x % mod, lst)) self.mod = mod self.normalize() def normalize(self): while self.poly and self.poly[-1] == 0: self.poly.pop() def arithm(self, p1, p2, op): len_p1, len_p2= len(p1.poly), len(p2.poly) res = [0] * max(len_p1, len_p2) if len_p1 > len_p2: for _ in range(len_p1-len_p2): p2.poly.append(0) else: for _ in range(len_p2-len_p1): p1.poly.append(0) for i in range(len(res)): res[i] = op(p1.poly[i], p2.poly[i]) % self.mod return Polynomial(res, self.mod) def __add__(self, p2): return self.arithm(self, p2, operator.add) def __sub__(self, p2): return self.arithm(self, p2, operator.sub) def __mul__(self, p2): res = [0]*(len(self.poly)+len(p2.poly)-1) for i, x1 in enumerate(self.poly): for j, x2 in enumerate(p2.poly): res[i+j] += x1 * x2 % self.mod return Polynomial(res, self.mod) def __truediv__(self, p2): p1 = self m = self.mod if len(p1.poly) < len(p2.poly): return p1 if len(p2.poly) == 0: raise ZeroDivisionError divisor_coeff = p2.poly[-1] divisor_exp = len(p2.poly) - 1 while len(p1.poly) >= len(p2.poly): max_coeff_p1 = p1.poly[-1] #wspolczynnik przy najwyzszej potedze try: tmp_coeff = modDiv(max_coeff_p1, divisor_coeff, m) except ZeroDivisionError as e: raise e tmp_exp = len(p1.poly)-1 - divisor_exp '''tmp to pomocniczy wielomian o reprezentacji [0, 0, .., c^n], gdzie c^n to mnożnik w danym kroku algorytmu dzielenia w słupku. Następnie mnożymy go z wielomianem-dzielnikiem (p2) i odejmujemy (sub) od wielomianu-dzielnej (p1)''' tmp = [] for i in range(tmp_exp): tmp.append(0) tmp.append(tmp_coeff) sub = Polynomial(tmp, m) * p2 p1 = p1 - sub p1.normalize() #obcinamy zbędne zera dopisane do wielomianu podczas odejmowania return Polynomial(p1.poly, m) def poly_gcd(self, p2): p1 = self try: divisible = p2 except ZeroDivisionError as e: raise e if p2.poly == []: return p1 return p2.poly_gcd(p1 / p2) def modDiv(a, b, m): # a*b^-1 (mod m) if gcd(b, m) != 1: raise ZeroDivisionError else: return (a * modinv(b, m)) % m #rozszerzony algorytm euklidesa def egcd(a, b): if a == 0: return (b, 0, 1) else: g, y, x = egcd(b % a, a) return (g, x - (b // a) * y, y) def modinv(a, m): g, x, y = egcd(a, m) return x % m def main(): n, p1, p2 = int(sys.argv[1]), ast.literal_eval(sys.argv[2]), ast.literal_eval(sys.argv[3]) P1 = Polynomial(p1, n) P2 = Polynomial(p2, n) mul = (P1 * P2).poly try: div = (P1 / P2).poly except ZeroDivisionError as e: div = e try: gcd = P1.poly_gcd(P2).poly except ZeroDivisionError as e: gcd = e print([mul, div, gcd]) if __name__ == '__main__': main()