use std::collections::HashMap;

/*
struct primes {
    primes : Vec<u32>,
    root_n : usize,
}

impl primes {
    fn get(&self, index: usize) -> u64 {
        return self.primes[index] as u64;
    }
    fn new(root_n: usize) -> Self {
        let mut v = Vec::with_capacity(1024);
        v.push(2u32);
        for cur in 2 ..= root_n {
            {
                let res = v.iter().find(|&v| cur as u32 % *v == 0);
                if res.is_some() {
                    continue;
                }
            }
            v.push(cur as u32);
        }
        primes {
            root_n: root_n,
            primes : v,
        }
    }
}

fn collect_primes3(n: u64, memo: & primes) -> HashMap<u64, u32> {
    let mut primes_div = HashMap::<u64, u32>::new();

    let mut val = n;
    let mut idx = 0;
    while val != 1u64 {
        let prime = memo.get(idx) as u64;
        if val % prime == 0 {
            val /= prime;
            *(primes_div.entry(prime as u64).or_insert(0)) += 1;
            continue;
        }
        idx += 1;
    }
    primes_div
}

*/

#[derive(Debug)]
struct seive_prime {
    primes: Vec<u32>,
    max_prime: u32,
    cur : usize,
}

#[inline(always)]
fn prime_to_bit_idx(p: usize) -> usize {
    (p - 1) / 32
}

#[inline(always)]
fn prime_to_bit_offset(p: usize) -> usize {
    (p - 1) % 32
}

#[inline(always)]
fn clear_prime(primes: &mut Vec<u32>, p:usize)  {
    // println!("p={} index={}   0b{:032b}  offset = {}", p, prime_to_bit_idx(p), prime_to_bit_offset(p), primes[prime_to_bit_idx(p)] );
    primes[ prime_to_bit_idx(p) ] |= 1u32 << prime_to_bit_offset(p);
}

#[inline(always)]
fn is_prime(primes: &Vec<u32>, p: usize) -> bool {
    0x0 == ((primes[ prime_to_bit_idx(p) ] >> prime_to_bit_offset(p) ) & 0x1)
}

impl seive_prime {
    fn new(n: usize) -> Self {
        let root_n = (n as f64).sqrt().ceil() as usize;
        let mut v   = vec![0x0u32; ((n+1) / 32) + 1];
        let mut cur = 2 as usize;
        // outer
        while cur < root_n {
            if is_prime(&v, cur) {
                let step = cur;
                let mut index = cur;
                index += step;
                while index <= n {
                    clear_prime(&mut v, index);
                    index += step;
                }
            }
            cur += 1;
        }
        seive_prime {
            primes : v,
            max_prime : n as u32,
            cur : 2,
        }
    }
    fn reset(&mut self) {
        self.cur = 2;
    }
}
impl Iterator for seive_prime {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        while self.cur <= self.max_prime as usize {
            if ! is_prime(&self.primes, self.cur) {
                self.cur += 1;
                continue;
            }
            let ret = self.cur;
            self.cur += 1;
            return Some(ret);
        }
        None
    }
}

#[test]
fn test_seive() {
    let s = seive_prime::new(1000); // 33 + 1 => 34
    // 1,2,3,5,7,11
    let p1 = 3;
    assert_eq!(prime_to_bit_idx(p1), 0);
    assert_eq!(prime_to_bit_offset(p1), 2);
    let p2 = 33;
    assert_eq!(prime_to_bit_idx(p2), 1);
    assert_eq!(prime_to_bit_offset(p2), 0);
    let p3 = 997;
    assert_eq!(prime_to_bit_idx(p3), 31);
    assert_eq!(prime_to_bit_offset(p3), 4);
    // iterator
    let expected = vec![2,3,5,7,11,13];
}


fn collect_primes2(n: u64, s: & mut seive_prime) -> HashMap<u64, u32> {
    let mut primes = HashMap::<u64, u32>::new();
    if n == 1 {
        primes.insert(1, 1);
        return primes;
    }
    let mut i: usize = 2;
    let mut cur = n;
    while cur != 1 {
        if cur % i as u64  == 0 {
            cur /= i as u64;
            *(primes.entry(i as u64).or_insert(0)) += 1;
            continue;
        }
        i  = s.next().unwrap();
    }

    primes
}

fn collect_primes(n: u64) -> HashMap<u64, u32> {
    let mut primes = HashMap::<u64, u32>::new();
    let mut cur = n;
    let mut i = 2_u64;
    if n == 1 {
        primes.insert(1, 1);
        return primes;
    }
    while cur != 1 {
        if cur % i  == 0 {
            *(primes.entry(i).or_insert(0)) += 1;
            cur /= i;
            continue;
        }
        i += 1;
    }

    primes
}


fn union_primes(l: HashMap<u64, u32>, r: HashMap<u64,u32>) -> HashMap<u64,u32>{
    let mut nprimes = l.clone();
    let t = 0;
    for p1 in l.keys() {
        let lp = l.get(p1).unwrap();
        let rp = r.get(p1).unwrap_or(&t);
        if lp > rp {
            nprimes.insert(*p1, *lp);
        } else {
            nprimes.insert(*p1, *rp);
        }
    }
    for p2 in r.keys() {
        let n = *(nprimes.get(p2).unwrap_or(&0));
        let rp = r.get(p2).unwrap();
        if n < *rp {
            nprimes.entry(*p2).or_insert(*rp);
        }
    }
    nprimes
}

macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        let mut next = || { iter.next().unwrap() };
        input_inner!{next, $($r)*}
    };
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes
                .by_ref()
                .map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};

    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

macro_rules! read_value {
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };

    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };

    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };

    ($next:expr, usize1) => {
        read_value!($next, usize) - 1
    };

    ($next:expr, $t:ty) => {
        $next().parse::<$t>().expect("Parse error")
    };
}

fn gcd(l :u64, r: u64) -> u64 {
    if l < r {
        return gcd(r, l);
    }
    if r == 0 {
        return l;
    }
    gcd(l % r, r)
}

#[test]
fn test_gcd() {
    assert_eq!( gcd(10,8),  2);
    assert_eq!( gcd(20,5),  5);
    assert_eq!( gcd(33,7),  1);
    assert_eq!( gcd(12,8),  4);
}

fn main() {
    input! {
        n : usize,
        tx : [[u64; 1]; n],
    }
    // println!("try prime 2 .. n ");
    let mut base = 1u64;
    for i in 0..n {
        let time_i = tx[i][0];
        base = (base as u64 / gcd(base, time_i)) * time_i;
        // println!("lcm = {:?}", base);
    }
    // println!("ans {:?}", base);

/*
    println!("---------------------------");
    println!("enestra furui prime ");
    let mut base2 = HashMap::<u64,u32>::new();
    let mut tx2 = (0..n).map(|i| tx[i][0]).collect::<Vec<_>>();
    tx2.sort();
    println!("{:?} {} {}", tx2, tx2.len(), tx2[tx2.len() - 1]);

    let prime_max = ((tx2[tx2.len() - 1] ) as f64).sqrt().ceil() as usize + 1;
    let mut s = seive_prime::new( prime_max );
    // println!("s = {:?}", s);
    for i in 0 .. n {
        let prime = collect_primes2( tx2[i], &mut s );
        base2 = union_primes(base2, prime);
        s.reset();
    }
*/
/*
    let root_n : usize = (tx2[tx2.len() -1] as f64).sqrt().ceil() as usize + 1;
    let primes = primes::new(root_n);
    for i in 0 .. n {
        let pd = collect_primes3(tx2[i], &primes);
        base2 = union_primes(base2, pd);
        println!("p2 {:?}", base2);
    }
    */

    //let mut ans = 1u64;
    /*
    for (k,v) in base.iter() {
        println!("{} {}", k,v);
        ans *= (*k as u64).pow(*v);
        println!("ans {} ", ans);
    }
    */
    /*
    let mut ans2 = 1u64;
    for (k,v) in base2.iter() {
        println!("{} {}", k,v);
        ans2 *= (*k as u64).pow(*v);
        println!("ans {} ", ans2);
    }
    */

    // println!("ans   {}", ans);
    // println!("ans2  {}", ans2);
    println!("{}", base);
}


Measured memory_bytes: 4352