use std::io::*;
use std::str::FromStr;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

fn large_mul_mod(mut lhs: i64, mut rhs: i64, modulo: i64) -> i64 {
    let mut ret = 0i64;
    while rhs > 0 {
        if (rhs & 1) == 1 {
            ret = (ret + lhs) % modulo;
        }
        rhs >>= 1;
        lhs = (lhs + lhs) % modulo;
    }
    ret
}

fn pow_mod(mut base: i64, mut power: i64, modulo: i64) -> i64 {
    let mut ans = 1i64;
    if modulo < (1 << 30) {
        while power > 0 {
            if (power & 1) == 1 {
                ans = ans * base % modulo;
            }
            power >>= 1;
            base = base * base % modulo;
        }
    } else {
        while power > 0 {
            if (power & 1) == 1 {
                ans = large_mul_mod(ans, base, modulo);
            }
            power >>= 1;
            base = large_mul_mod(base, base, modulo);
        }
    }
    ans
}

fn suspect(t: i64, mut s: i64, d: i64, n: i64) -> bool {
    let mut x = pow_mod(t, d, n);
    if x == 1 {
        return true;
    }
    while s > 0 {
        s -= 1;
        if x == n - 1 {
            return true;
        }
        if n < (1 << 30) {
            x = x * x % n;
        } else {
            x = large_mul_mod(x, x, n);
        }
    }
    false
}

#[allow(dead_code)]
fn is_prime(n: i64) -> bool {
    if n <= 1 || (n > 2 && n % 2 == 0) {
        return false;
    }
    let mut d = n - 1;
    let mut s = 0;
    while (d & 1) == 0 {
        s += 1;
        d >>= 1;
    }
    // let test = [2, 7, 61, 1i64 << 60]; // is for n < 2^32
    let test = [2, 3, 5, 7, 11, 13, 17, 19, 23, 1i64 << 60]; // is for n < 10^16 (at least)
    for &t in test.iter() {
        if t >= n {
            break;
        }
        if !suspect(t, s, d, n) {
            return false;
        }
    }
    true
}

#[test]
fn test_is_prime() {
    assert!(is_prime(2));
    assert!(is_prime(3));
    assert!(is_prime(5));
    assert!(is_prime(7));
    assert!(is_prime(11));
    assert!(is_prime(103));
    assert!(is_prime(1000000007));
    assert!(is_prime(1000000009));
    assert!(is_prime(3478329271));
    assert!(is_prime(777177177781));
    assert!(is_prime(67280421310721));

    assert!(!is_prime(-1));
    assert!(!is_prime(0));
    assert!(!is_prime(1));
    assert!(!is_prime(4));
    assert!(!is_prime(9));
    assert!(!is_prime(77));
    assert!(!is_prime(1000000001));
    assert!(!is_prime(4002002002));
    assert!(!is_prime(7478329271));
    assert!(!is_prime(1357436473381));
}

type Weight = i32;
#[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct Edge {
    index: usize,
    src: usize,
    dest: usize,
    weight: Weight,
}
#[allow(dead_code)]
impl Edge {
    fn new(index: usize, src: usize, dest: usize, weight: Weight) -> Edge {
        Edge {
            index: index,
            src: src,
            dest: dest,
            weight: weight,
        }
    }
}
impl std::cmp::Ord for Edge {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        (self.weight, self.src, self.dest).cmp(&(other.weight, other.src, other.dest))
    }
}
impl std::cmp::PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
type Edges = Vec<Edge>;
type Graph = Vec<Edges>;
#[allow(dead_code)]
fn graph_new(n: usize) -> Graph {
    vec![vec![]; n]
}

use std::collections::VecDeque;
// index ^ 1 is reverse edge
#[allow(dead_code)]
fn add_bi_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    *index += 1;
    graph[dest].push(Edge::new(*index, dest, src, weight));
    *index += 1;
}
#[allow(dead_code)]
fn add_uni_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    *index += 1;
    graph[dest].push(Edge::new(*index, dest, src, 0));
    *index += 1;
}

#[allow(dead_code)]
fn augment(
    g: &Graph,
    capacity: &mut Vec<Weight>,
    level: &Vec<usize>,
    finished: &mut Vec<bool>,
    from: usize,
    t: usize,
    cur: Weight,
) -> Weight {
    if from == t || cur == 0 {
        return cur;
    }
    if finished[from] {
        return 0;
    }
    for edge in g[from].iter() {
        let to = edge.dest;
        if level[to] != level[from] + 1 {
            continue;
        }
        let ncur = std::cmp::min(cur, capacity[edge.index]);
        let f = augment(g, capacity, level, finished, to, t, ncur);
        if f > 0 {
            capacity[edge.index] -= f;
            capacity[edge.index ^ 1] += f;
            return f;
        }
    }
    finished[from] = true;
    0
}

#[allow(dead_code)]
fn max_flow(g: &Graph, e: usize, s: usize, t: usize) -> Weight {
    let n = g.len();
    let mut capacity: Vec<Weight> = vec![0; e];
    for from in 0..n {
        for edge in g[from].iter() {
            capacity[edge.index] += edge.weight;
        }
    }
    let mut ans = 0;
    loop {
        let mut level = vec![usize::max_value(); n];
        level[s] = 0;
        let mut que = VecDeque::<usize>::new();
        que.push_back(s);
        while let Some(from) = que.pop_front() {
            if from == t {
                break;
            }
            for edge in g[from].iter() {
                let to = edge.dest;
                if capacity[edge.index] > 0 && level[to] == usize::max_value() {
                    que.push_back(to);
                    level[to] = level[from] + 1;
                }
            }
        }
        let mut finished = vec![false; n];
        let mut end = true;
        loop {
            let f = augment(
                g,
                &mut capacity,
                &level,
                &mut finished,
                s,
                t,
                Weight::max_value(),
            );
            if f == 0 {
                break;
            }
            ans += f;
            end = false;
        }
        if end {
            break;
        }
    }
    ans
}

fn main() {
    let n = read::<usize>();
    let mut seq = vec![0i64; n];
    for i in 0..n {
        seq[i] = read::<i64>();
    }
    let mut start = -1;
    let mut positions = vec![];
    for i in 0..n {
        if start == -1 {
            start = seq[i];
        }
        if i == n - 1 || seq[i] + 1 != seq[i + 1] {
            positions.push(start);
            positions.push(seq[i] + 1);
            start = -1;
        }
    }
    // println!("{:?}", positions);
    let n = positions.len();
    let source = n;
    let dest = n + 1;
    let size = n + 2;
    let mut graph = graph_new(size);
    let mut e = 0;
    let mut odd_cnt = 0;
    let mut even_cnt = 0;
    for i in 0..n {
        let pos = positions[i];
        if pos % 2 == 0 {
            odd_cnt += 1;
            add_uni_edge(&mut graph, &mut e, source, i, 1);
            for j in 0..n {
                let d = (positions[j] - pos).abs();
                if d > 2 && is_prime(d) {
                    // println!("{} {}", std::cmp::min(pos, positions[j]), std::cmp::max(pos, positions[j]));
                    add_uni_edge(&mut graph, &mut e, i, j, 1);
                }
            }
        } else {
            even_cnt += 1;
            add_uni_edge(&mut graph, &mut e, i, dest, 1);
        }
    }
    let flow = max_flow(&graph, e, source, dest);
    let mut ans = flow + (odd_cnt - flow) / 2 * 2 + (even_cnt - flow) / 2 * 2;
    if (odd_cnt - flow) % 2 == 1 {
        ans += 3;
    }
    println!("{}", ans);
}


Measured memory_bytes: 4352