Problem:
Score : 1200 points

Problem Statement

There are infinitely many cards, numbered 1, 2, 3, ...
Initially, Cards x_1, x_2, ..., x_N are face up, and the others are face down.

Snuke can perform the following operation repeatedly:

Select a prime p greater than or equal to 3. Then, select p consecutive cards and flip all of them.

Snuke's objective is to have all the cards face down.
Find the minimum number of operations required to achieve the objective.

Constraints

1 ≤ N ≤ 100

1 ≤ x_1 < x_2 < ... < x_N ≤ 10^7

Input

Input is given from Standard Input in the following format:

N
x_1 x_2 ... x_N

Output

Print the minimum number of operations required to achieve the objective.

Sample Input 1

2
4 5

Sample Output 1

2

Below is one way to achieve the objective in two operations:

Select p = 5 and flip Cards 1, 2, 3, 4 and 5.

Select p = 3 and flip Cards 1, 2 and 3.

Sample Input 2

9
1 2 3 4 5 6 7 8 9

Sample Output 2

3

Below is one way to achieve the objective in three operations:

Select p = 3 and flip Cards 1, 2 and 3.

Select p = 3 and flip Cards 4, 5 and 6.

Select p = 3 and flip Cards 7, 8 and 9.

Sample Input 3

2
1 10000000

Sample Output 3

4

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Accepted)

import java.io.*;
import java.util.*;

public class Main {

	boolean dfs(int v, int[] pair, boolean[] vis, boolean[][] g) {
		vis[v] = true;
		for (int u = 0; u < g[v].length; u++) {
			if (!g[v][u]) {
				continue;
			}
			if (pair[u] == -1 || (!vis[pair[u]] && dfs(pair[u], pair, vis, g))) {
				pair[u] = v;
				return true;
			}
		}
		return false;
	}

	void submit() {
		 int n = nextInt();
		 int[] xs = new int[n];
		 for (int i = 0; i < n; i++) {
		 xs[i] = nextInt();
		 }

//		int n = 100;
//		int[] xs = new int[n];
//		for (int i = 0; i < n; i++) {
//			xs[i] = 2 * i + 1;
//		}

		TreeSet<Integer> init = new TreeSet<>();

		for (int i = 0; i < n; i++) {
			if (i == 0 || (xs[i - 1] != xs[i] - 1)) {
				init.add(xs[i] - 1);
			}
			if (i == n - 1 || (xs[i + 1] != xs[i] + 1)) {
				init.add(xs[i]);
			}
		}

		// System.err.println(init);

		boolean[] isPrime = new boolean[10_000_001];
		Arrays.fill(isPrime, true);
		isPrime[0] = isPrime[1] = false;

		for (int i = 2; i * i < isPrime.length; i++) {
			if (isPrime[i]) {
				for (int j = i * i; j < isPrime.length; j += i) {
					isPrime[j] = false;
				}
			}
		}

		List<Integer>[] byPar = new ArrayList[2];
		byPar[0] = new ArrayList<>();
		byPar[1] = new ArrayList<>();

		for (int x : init) {
			byPar[x % 2].add(x);
		}

		boolean[][] g = new boolean[byPar[0].size()][byPar[1].size()];
		for (int i = 0; i < byPar[0].size(); i++) {
			int x = byPar[0].get(i);
			for (int j = 0; j < byPar[1].size(); j++) {
				int y = byPar[1].get(j);

				g[i][j] = isPrime[Math.abs(x - y)];
			}
		}

		int[] pair = new int[byPar[1].size()];
		Arrays.fill(pair, -1);
		boolean[] vis = new boolean[byPar[0].size()];

		int match = 0;
		for (int i = 0; i < g.length; i++) {
			Arrays.fill(vis, false);
			if (dfs(i, pair, vis, g)) {
				match++;
			}
		}

		int part1 = byPar[0].size();
		int part2 = byPar[1].size();

		int ans = match + go(part1 - match, part2 - match);
		if (match > 0) {
			match--;
			ans = Math.min(ans, match + go(part1 - match, part2 - match));
		}

		out.println(ans);
	}

	int go(int x, int y) {
		if ((x % 2) != (y % 2)) {
			throw new AssertionError();
		}
		if (x % 2 == 0) {
			return x + y;
		} else {
			return x + y + 1;
		}
	}

	void preCalc() {

	}

	void stress() {

	}

	void test() {

	}

	Main() throws IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		preCalc();
		submit();
		// stress();
		// test();
		out.close();
	}

	static final Random rng = new Random();

	static int rand(int l, int r) {
		return l + rng.nextInt(r - l + 1);
	}

	public static void main(String[] args) throws IOException {
		new Main();
	}

	BufferedReader br;
	PrintWriter out;
	StringTokenizer st;

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
		return st.nextToken();
	}

	String nextString() {
		try {
			return br.readLine();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	int nextInt() {
		return Integer.parseInt(nextToken());
	}

	long nextLong() {
		return Long.parseLong(nextToken());
	}

	double nextDouble() {
		return Double.parseDouble(nextToken());
	}
}