import math from functools import reduce def gen_odd(): n = 3 while True: yield n n += 2 def primes(): yield 2 g = gen_odd() while True: prime = next(g) s_prime = prime * prime ps = [] while s_prime != prime: yield prime ps.append(prime) prime = next(g) pred = lambda x, ps = ps: all(x % p for p in ps) g = filter(pred, g) def divl(ns, p, rangen): mods = [n % p for n in ns] if all(m for m in mods): # 全ての n の素因数じゃなかったので次の素数へ return ns, False else: # p がいずれかの n の素因数だったので、割れるものを割る ns = [ns[i] if mods[i] else (ns[i] // p) for i in rangen] return ns, True def lcm(ns): """ 最小公倍数を求める """ ps = primes() p = next(ps) rangen = list(range(len(ns))) nn = [] while True: max_n = max(*ns) max_bound = int(math.sqrt(max_n)) if p > max_bound: break ns, divable = divl(ns, p, rangen) if divable: # p がいずれかの n の素因数だったので、割れるものを割る nn.append(p) else: # 全ての n の素因数じゃなかったので次の素数へ p = next(ps) # 残った数で割る for i in rangen: ni = ns[i] ns, divable = divl(ns, ni, rangen) if divable: nn.append(ni) # 全ての割れた素数と残った値を掛ける lp = reduce(lambda a, b: a * b, nn, 1) ln = reduce(lambda a, b: a * b, ns, 1) return lp * ln def solve(N, K, xys): # 1回のループで各位置がどこに移動するのか求める # M[i] は i 番目の棒が1回のループでどこに移動するか M = list(range(N)) for i in range(K): xi, yi = xys[i] M[xi], M[yi] = M[yi], M[xi] # 各縦棒のループ数値が何回で元の位置に戻るかを計算 O(?) L = [] for n in range(N): p = M[n] l = 1 while p != n: p = M[p] l += 1 L.append(l) # 各縦棒のループ数の最小公倍数が答え return lcm(L) def main(): N = int(input()) K = int(input()) xys = [] for i in range(K): x, y = map(int, input().split()) xys.append((x - 1, y - 1)) a = solve(N, K, xys) print(a) if __name__ == '__main__': main()