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 C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)


#include <bits/stdc++.h>

#define FOR(i,b,e) for(int i=(b); i <= (e); ++i)
#define FORD(i,b,e) for(int i=(b); i >= (e); --i)
#define SIZE(c) (int) (c).size()
#define FORE(i,c) FOR(i,0,SIZE(c)-1)
#define FORDE(i,c) FORD(i,SIZE(c)-1,0)

#define pb push_back
#define mp make_pair
#define st first
#define nd second


using namespace std;

typedef long long ll;
typedef pair <int,int> pii;
typedef pair <ll,ll> pll;

typedef vector <int> VI;
typedef vector <bool> VB;
typedef vector <pii> VP;
typedef vector <ll> VL;
typedef vector <pll> VPL;

typedef vector <VI> VVI;
typedef vector <VL> VVL;
typedef vector <VB> VVB;
typedef vector <VP> VVP;

struct MinCostFlow {
    typedef int capacity_t;
    typedef int cost_t;

    // use INFINITY from cmath if cost_t is a double
    const cost_t INF = 1000 * 1000 * 1000;
    const capacity_t MAX_CAP = 1000 * 1000 * 1000;

    struct edge {
        int from, v;
        capacity_t cap, flow;
        cost_t cost, dist;
        int rev_index;
        
        bool residual() { return flow < cap; }
        
        edge(int _f, int _v, capacity_t _cap, cost_t _cost):
            from(_f), v(_v), cap(_cap), flow(0), cost(_cost), dist(_cost) {}
    };

    int n, s, t;
    vector <cost_t> d;
    vector <edge*> p;
    vector <vector<edge>> g;
    VB queued;
    
    MinCostFlow(int n): n(n), d(n), p(n), g(n), queued(n) {}
    
    void bellman() {
        FOR(i,0,n-1) { d[i] = INF; queued[i] = 0; }
        queue <int> q;
        
        d[s] = 0;
        q.push(s); queued[s] = 0;
        
        while (!q.empty()) {
            int u = q.front(); q.pop(); queued[u] = 0;
            
            for (auto &i : g[u]) if (i.residual() && d[i.v] > d[u] + i.dist) {
                d[i.v] = d[u] + i.dist;
                p[i.v] = &i;
                if (!queued[i.v]) { q.push(i.v); queued[i.v] = 1; }
            }
        }
    }

    pair <capacity_t,cost_t> computeFlow(int s, int t) {
        this->s = s;
        this->t = t;

        capacity_t flow = 0;
        cost_t cost = 0;

        while (true) {
            bellman();

            if (d[t] == INF) break;
            cost_t c = 0;
            capacity_t f = MAX_CAP;
            
            for (int u=t; u!=s; u=p[u]->from) {
                f = min(f, p[u]->cap - p[u]->flow);
            }
            
            for (int u=t; u!=s; u=p[u]->from) {
                p[u]->flow += f;
                g[p[u]->v][p[u]->rev_index].flow -= f;
                c += p[u]->cost;
            }
            
            flow += f; cost += f * c;
        }
        
        return {flow, cost};
    }
    
    void addEdge(int a, int b, capacity_t f, cost_t c) {
        assert(a != b);
        
        g[a].pb(edge(a, b, f, c));
        g[b].pb(edge(b, a, 0, -c));
        g[a].back().rev_index = SIZE(g[b])-1;
        g[b].back().rev_index = SIZE(g[a])-1;
    }
};

/*************************************************************************/

bool isPrime(int x) {
    if (x == 1) return false;

    for (int i = 2; i * i <= x; i++) if (x % i == 0) {
        return false;
    }
    
    return true;
}


struct TurboMatching {
    int value = 0;

    VVI G;
    VI mate; VB vis;

    TurboMatching(int n): G(n), mate(n,-1), vis(n,0) {}

    void addEdge(int u, int v) {
        G[u].pb(v);
        G[v].pb(u);
    }

    bool findPath(int v) {
        if (vis[v]) return false;
        vis[v] = true;

        for (int u : G[v]) if (mate[u] == -1 || findPath(mate[u])) {
            mate[v] = u;
            mate[u] = v;
            return true;
        }

        return false;
    }

    pair <int,VI> runMatching() {
        while (true) {
            bool found = false;
            FORE(v,G) vis[v] = false;

            FORE(v,G) if (mate[v] == -1 && findPath(v)) {
                found = true;
                value++;
            }

            if (!found) break;
        }

        return {value, mate};
    }
};

/*************************************************************************/

int solve(int n, VI &x) {
    TurboMatching matching(n);
    
    FOR(i,0,n-1) FOR(j,i+1,n-1) {
        int diff = abs(x[i] - x[j]);
        
        if (diff % 2 && isPrime(diff)) {
            matching.addEdge(i, j);
        }
    }
    
    int matchingInOnes = matching.runMatching().st;
    
    int odd = 0, even = 0;
    FOR(i,0,n-1) {
        if (x[i] % 2) odd++;
        else even++;
    }

    int ans = matchingInOnes;
    ans += 2 * (odd / 2);
    ans += 2 * (even / 2);
    
    if (odd % 2) {
        ans += 3;
    }
    
    return ans;
}

/*************************************************************************/

int main() {
    ios_base::sync_with_stdio(0);
    
    int n;
    cin >> n;
    
    set <int> pos;
    while (n--) {
        int x;
        cin >> x;
        
        VI vals = {x-1, x};
        for (int v : vals) {
            if (pos.count(v)) {
                pos.erase(v);
            } else {
                pos.insert(v);
            }
        }
    }
    
    VI posVec(pos.begin(), pos.end());
    cout << solve(posVec.size(), posVec);

    return 0;
}

/*************************************************************************/