from itertools import combinations


def primal_numbers(n):
    a = [True for i in range(n + 1)]
    a[0] = False
    a[1] = False
    out = []
    for i in range(2, n + 1):
        if not a[i]:
            continue
        out.append(i)
        for j in range(i, n + 1, i):
            a[j] = False
    return out


def factorize_number(n, primlist, primset):
    out = []
    while n not in primset:
        for p in primlist:
            if n % p == 0:
                out.append(p)
                n //= p
                break
        else:
            break
    if not out:
        return None
    if n != 1:
        out.append(n)
    return out


def product(*a):
    r = 1
    for x in a:
        r *= x
    return r


def step_count(step, k):
    shift = step % k
    a, r = 0, 0
    while True:
        r += 1
        a += shift
        if a >= k:
            a -= k
        if a == 0:
            return r


def check_result_set(value, mset):
    for i in mset:
        if value % i != 0:
            return False
    return True


def find_divisible_by_set(mset, simple=False, debug=False):
    plist = primal_numbers(max(mset))
    pset = set(plist)

    step_mults = mset & pset
    step = product(*list(step_mults))
    if debug:
        print('STEP MULT', sorted(step_mults))
        print('STEP', step)

    ax = set()
    for j in mset:
        f = factorize_number(j, plist, pset)
        if f is None:
            continue
        ax.update(f)
        for k in range(2, len(f)):
            for comb in combinations(f, k):
                ax.add(product(*comb))
    if debug:
        print('ALL POSSIBLE FACTORIZATION MULTIPLIERS', list(reversed(sorted(list(ax)))))
    ax = mset - ax
    if debug:
        print('INVERTED', list(reversed(sorted(list(ax)))))
    ax = ax - step_mults
    if debug:
        print('REMOVED PRIMALS (THEY ARE ALL INCLUDED IN STEP)', list(reversed(sorted(list(ax)))))

    discards = []
    for k in ax:
        if step % k == 0:
            discards.append(k)
    for k in discards:
        ax.discard(k)
    if debug:
        print('FILTERED BY STEP MOD', list(reversed(sorted(list(ax)))))

    max_result = product( *list(ax | step_mults) )
    assert check_result_set(max_result, mset)
    if debug:
        print('WORST CASE RESULT', max_result)
        print('ITER COUNT', max_result // step)

    ax = list(reversed(sorted(list(ax))))

    if simple:
        i = step
        while True:
            for k in ax:
                if i % k != 0:
                    break
            else:
                break
            i += step
        if debug:
            print('RESULT', i)
        return i
    else:
        sset = set()
        for k in ax:
            # print(k, step % k, step_count(step, k))
            sset.add(step_count(step, k))
        if debug:
            print('STEPS SET', sorted(list(sset)))
            print('RECURSING IN...')
        fx = find_divisible_by_set(sset, simple=True)
        if debug:
            print('RECURSING OUT...')
        return step * fx


# from sys import argv
# N = int(argv[1])

N = 300

Nset = set(range(2, N + 1))
x = find_divisible_by_set(Nset)
assert check_result_set(x, Nset)
print(x)