/*
ID: kfoozminus
TASK:
LANG: C++
*/

#include <bits/stdc++.h>
using namespace std;
//typedefs
/*
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <int, pii> piii;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
const double PI = acos(-1);
*/
//typedefs
#define ll long long
#define ull unsigned long long
#define pii pair <int, int>
#define piii pair <int, pii>
#define vi vector <int>
#define vl vector <ll>
#define pll pair <ll, ll>
#define PI acos(-1)
//defines
#define MP make_pair
#define PB push_back
#define F first
#define S second
#define mem(a, b) memset(a, b, sizeof(a))
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) (a*(b/gcd(a,b)))
#define SQR(a) ((a)*(a))
#define inf 100000000
#define mod 1000000007
#define mod1 1000000007
#define mod2 1000000009
#define b1 43
#define b2 41
#define EPS 1e-9
//define harmonic(n) 0.57721566490153286l+log(n)
#define nl puts("")
#define odd(n) ((n)&1)
#define even(n) (!((n)&1))
#define vsort(v) sort(v.begin(), v.end())
#define lc (node<<1)
#define rc ((node<<1)|1)
#define ran(a, b) ((((rand() << 15) ^ rand()) % ((b) - (a) + 1)) + (a))
//loop
#define rep(i, n) for(int i = 0; i < n; ++i)
#define REP(i, n) for(int i = 1; i <= n; ++i)
//input
#define si(a) scanf("%d", &a)
#define sii(a, b) scanf("%d%d", &a, &b)
#define siii(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define sl(a) scanf("%lld", &a)
#define sll(a, b) scanf("%lld%lld", &a, &b)
#define slll(a, b, c) scanf("%lld%lld%lld", &a, &b, &c)
#define sd(a) scanf("%lf", &a)
#define sc(a) scanf("%c", &a)
#define sst(a) scanf("%s", a)
inline bool EQ(double a, double b) { return fabs(a-b) < 1e-9; }
//debug
#ifdef kfoozminus

template < typename F, typename S >
ostream& operator << ( ostream& os, const pair< F, S > & p ) {
	return os << "(" << p.first << ", " << p.second << ")";
}

template < typename T >
ostream &operator << ( ostream & os, const vector< T > &v ) {
	os << "{";
	for(auto it = v.begin(); it != v.end(); ++it) {
		if( it != v.begin() ) os << ", ";
		os << *it;
	}
    return os << "}";
}

template < typename T >
ostream &operator << ( ostream & os, const set< T > &v ) {
	os << "[";
	for(auto it = v.begin(); it != v.end(); ++it) {
		if( it != v.begin()) os << ", ";
		os << *it;
	}
    return os << "]";
}

template < typename F, typename S >
ostream &operator << ( ostream & os, const map< F, S > &v ) {
	os << "[";
	for(auto it = v.begin(); it != v.end(); ++it) {
		if( it != v.begin() ) os << ", ";
		os << it -> first << " = " << it -> second ;
	}
    return os << "]";
}

#define dbg(args...) do {cerr << #args << " : "; faltu(args); } while(0)

clock_t tStart = clock();
#define timeStamp dbg("Execution Time: ", (double)(clock() - tStart)/CLOCKS_PER_SEC)

void faltu () { cerr << endl; }

template <typename T>
void faltu( T a[], int n ) {
	for(int i = 0; i < n; ++i) cerr << a[i] << ' ';
	cerr << endl;
}

template <typename T, typename ... hello>
void faltu( T arg, const hello &... rest) { cerr << arg << ' '; faltu(rest...); }

#else
#define dbg(args...)
#endif
/*
ll add(ll a, ll b) {
	ll ret = a+b;
	if(ret >= mod) ret -= mod;
	return ret;
}

ll subtract(ll a, ll b) {
	ll ret = a-b;
	if(ret < 0) ret += mod;
	return ret;
}

ll mult(ll a, ll b) {
	ll ret = a*b;
	if(ret >= mod) ret %= mod;
	return ret;
}

ll bigmod(ll a, ll b) {
	ll ret = 1;
	while(b) {
		if(b&1) ret = mult(ret, a);
		b >>= 1; a = mult(a, a);
	}
	return ret;
}
*/

//ll inverse(ll n) { return bigmod(n, mod-2); }

#define PMX 1000000

int marked[PMX/64 + 2];
vi primes;

#define mark(x) marked[x >> 6] |= (1 << ((x & 63) >> 1))
#define check(x) (marked[x >> 6] & (1 << ((x & 63) >> 1)))

bool isPrime(int x)
{
	return (x > 1) && ((x == 2) || ((x & 1) && (!(check(x)))));
}

void seive(int n)
{
	int i, j;
	for(i = 3; i * i <= n; i += 2) if(!check(i)) for(j = i * i; j <= n; j += i << 1) mark(j);
	primes.PB(2);
	for(i = 3; i <= n; i += 2) if(isPrime(i)) primes.PB(i);
}

//Direction Array
//int fx[]={1, -1, 0, 0}; int fy[]={0, 0, 1, -1};
//int fx[]={0, 0, 1, -1, -1, 1, -1, 1}; int fy[]={-1, 1, 0, 0, 1, 1, -1, -1};

//bit manipulation
/*
bool checkBit(int n, int i) { return (n&(1<<i)); }
int setBit(int n, int i) { return (n|(1<<i)); }
int resetBit(int n, int i) { return (n&(~(1<<i))); }
*/
//end of template

#define MX 100007
#define MXN 207
#define MXE 100007

int source, sink, NN, n, m;
int Q[MXN], fin[MXN], pro[MXN], dist[MXN], nEdge;
int flow[MXE], cap[MXE], nex[MXE], to[MXE];

void init()
{
	//src = _src, snk = _snk, nNode = _n, nEdge = 0;
	for(int i = 0; i <= NN; i ++) fin[i] = -1;
	nEdge = 0;
}

void addEdge(int u, int v, int c)
{
	to[ nEdge ] = v; cap[ nEdge ] = c; flow[ nEdge ] = 0; nex[ nEdge ] = fin[ u ]; fin[ u ] = nEdge ++;
	to[ nEdge ] = u; cap[ nEdge ] = 0; flow[ nEdge ] = 0; nex[ nEdge ] = fin[ v ]; fin[ v ] = nEdge ++;
}

bool bfs()
{ int st, en;

	for(int i = 0; i <= NN; i ++) dist[i] = -1;

	dist[source] = st = en = 0;

	Q[ en ++ ] = source;

	while(st < en) {

		int u = Q[ st ++ ];

		for(int i = fin[u]; i >= 0; i = nex[ i ]) {

			int v = to[ i ];
			if(flow[i] < cap[i] && dist[v] == -1) {

				dist[v] = dist[u] + 1;
				Q[ en ++ ] = v;
			}
		}
	}

	return dist[sink] != -1;
}

int dfs(int u, int fl)
{
	if(u == sink) return fl;

	for(int &i = pro[ u ]; i >= 0; i = nex[ i ]) {

		int v = to[ i ];

		if(flow[i] < cap[i] && dist[v] == dist[u] + 1) {

			int df = dfs(v, min(cap[ i ] - flow[ i ], fl) );

			if(df > 0) {

				flow[i] += df;
				flow[i ^ 1] -= df;

				return df;
			}
		}
	}
	return 0;
}

int dinic()
{
	int ret = 0;

	for(int i = 0; i < nEdge; i ++) flow[i] = 0;

	while( bfs() ) {

		for(int i = 0; i <= NN; i ++) pro[i] = fin[i];

		while(true) {

			int df = dfs(source, inf);
			if(df) ret += df;
			else break;
		}
	}
	return ret;
}

int a[MX];
vector<int> ans[MX];
int vis[MX], ed[300][300];

int main () {
#ifdef kfoozminus
//	freopen("in", "r", stdin);
//	freopen("out", "w", stdout);
#endif
	seive(100000);
	int odd = 0, even = 0, i, j;

	scanf("%d", &n);
	for(i = 0; i < n; i ++) {
		scanf("%d", &a[i]);
		if(a[i] & 1) odd ++;
		else even ++;
	}
	if(odd != even) {
		printf("Impossible\n");
		return 0;
	}

	source = 0;
	sink = n + 1;
	NN = sink;
	init();
	for(i = 0; i < n; i ++) {
		if(a[i] & 1) {
			addEdge(source, i + 1, 2);
		}
		else addEdge(i + 1, sink, 2);
		if(a[i] & 1) {
			for(j = 0; j < n; j ++) {
				if(isPrime(a[i] + a[j])) {
					addEdge(i + 1, j + 1, 1);
					//dbg(a[i] + a[j]);
				}
			}
		}
	}
	int p = dinic();
	dbg(p);
	int in = -1;
	if(p == 2 * even) {
		//printf("Possible\n");
		for(i = 1; i <= n; i ++) {
			//while(true) {
				for(j = fin[i]; j >= 0; j = nex[j]) {
					if(cap[j] == 2) continue;
					if(cap[j] == 1 && flow[j] == 1) {
						ed[i][ to[j] ] = 1;
						ed[ to[j] ][i] = 1;
						dbg(i, to[j]);
						//i = to[j];
						//break;
					}
				}
			//}
		}
		for(i = 1; i <= n; i ++) {
			if(vis[i] == 0) in ++;
			while(vis[i] == 0) {
				vis[i] = 1;
				ans[in].PB(i);
				for(j = 1; j <= n; j ++) {
					if(vis[j]) continue;
					if(ed[i][j]) {
						i = j;
						break;
					}
				}
			}
		}
		printf("%d\n", in + 1);
		for(i = 0; i <= in; i ++) {
			printf("%d ", ans[i].size());
			for(auto it : ans[i]) printf("%d ", it);
			nl;
		}
	}
	else printf("Impossible\n");

//	timeStamp;
	return 0;
}


/*
ID: kfoozminus
TASK:
LANG: C++
*/

#include <bits/stdc++.h>
using namespace std;
//typedefs
/*
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <int, pii> piii;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
const double PI = acos(-1);
*/
//typedefs
#define ll long long
#define ull unsigned long long
#define pii pair <int, int>
#define piii pair <int, pii>
#define vi vector <int>
#define vl vector <ll>
#define pll pair <ll, ll>
#define PI acos(-1)
//defines
#define MP make_pair
#define PB push_back
#define F first
#define S second
#define mem(a, b) memset(a, b, sizeof(a))
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) (a*(b/gcd(a,b)))
#define SQR(a) ((a)*(a))
#define inf 100000000
#define mod 1000000007
#define mod1 1000000007
#define mod2 1000000009
#define b1 43
#define b2 41
#define EPS 1e-9
//define harmonic(n) 0.57721566490153286l+log(n)
#define nl puts("")
#define odd(n) ((n)&1)
#define even(n) (!((n)&1))
#define vsort(v) sort(v.begin(), v.end())
#define lc (node<<1)
#define rc ((node<<1)|1)
#define ran(a, b) ((((rand() << 15) ^ rand()) % ((b) - (a) + 1)) + (a))
//loop
#define rep(i, n) for(int i = 0; i < n; ++i)
#define REP(i, n) for(int i = 1; i <= n; ++i)
//input
#define si(a) scanf("%d", &a)
#define sii(a, b) scanf("%d%d", &a, &b)
#define siii(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define sl(a) scanf("%lld", &a)
#define sll(a, b) scanf("%lld%lld", &a, &b)
#define slll(a, b, c) scanf("%lld%lld%lld", &a, &b, &c)
#define sd(a) scanf("%lf", &a)
#define sc(a) scanf("%c", &a)
#define sst(a) scanf("%s", a)
inline bool EQ(double a, double b) { return fabs(a-b) < 1e-9; }
//debug
#ifdef kfoozminus

template < typename F, typename S >
ostream& operator << ( ostream& os, const pair< F, S > & p ) {
	return os << "(" << p.first << ", " << p.second << ")";
}

template < typename T >
ostream &operator << ( ostream & os, const vector< T > &v ) {
	os << "{";
	for(auto it = v.begin(); it != v.end(); ++it) {
		if( it != v.begin() ) os << ", ";
		os << *it;
	}
    return os << "}";
}

template < typename T >
ostream &operator << ( ostream & os, const set< T > &v ) {
	os << "[";
	for(auto it = v.begin(); it != v.end(); ++it) {
		if( it != v.begin()) os << ", ";
		os << *it;
	}
    return os << "]";
}

template < typename F, typename S >
ostream &operator << ( ostream & os, const map< F, S > &v ) {
	os << "[";
	for(auto it = v.begin(); it != v.end(); ++it) {
		if( it != v.begin() ) os << ", ";
		os << it -> first << " = " << it -> second ;
	}
    return os << "]";
}

#define dbg(args...) do {cerr << #args << " : "; faltu(args); } while(0)

clock_t tStart = clock();
#define timeStamp dbg("Execution Time: ", (double)(clock() - tStart)/CLOCKS_PER_SEC)

void faltu () { cerr << endl; }

template <typename T>
void faltu( T a[], int n ) {
	for(int i = 0; i < n; ++i) cerr << a[i] << ' ';
	cerr << endl;
}

template <typename T, typename ... hello>
void faltu( T arg, const hello &... rest) { cerr << arg << ' '; faltu(rest...); }

#else
#define dbg(args...)
#endif
/*
ll add(ll a, ll b) {
	ll ret = a+b;
	if(ret >= mod) ret -= mod;
	return ret;
}

ll subtract(ll a, ll b) {
	ll ret = a-b;
	if(ret < 0) ret += mod;
	return ret;
}

ll mult(ll a, ll b) {
	ll ret = a*b;
	if(ret >= mod) ret %= mod;
	return ret;
}

ll bigmod(ll a, ll b) {
	ll ret = 1;
	while(b) {
		if(b&1) ret = mult(ret, a);
		b >>= 1; a = mult(a, a);
	}
	return ret;
}
*/

//ll inverse(ll n) { return bigmod(n, mod-2); }

#define PMX 1000000

int marked[PMX/64 + 2];
vi primes;

#define mark(x) marked[x >> 6] |= (1 << ((x & 63) >> 1))
#define check(x) (marked[x >> 6] & (1 << ((x & 63) >> 1)))

bool isPrime(int x)
{
	return (x > 1) && ((x == 2) || ((x & 1) && (!(check(x)))));
}

void seive(int n)
{
	int i, j;
	for(i = 3; i * i <= n; i += 2) if(!check(i)) for(j = i * i; j <= n; j += i << 1) mark(j);
	primes.PB(2);
	for(i = 3; i <= n; i += 2) if(isPrime(i)) primes.PB(i);
}

//Direction Array
//int fx[]={1, -1, 0, 0}; int fy[]={0, 0, 1, -1};
//int fx[]={0, 0, 1, -1, -1, 1, -1, 1}; int fy[]={-1, 1, 0, 0, 1, 1, -1, -1};

//bit manipulation
/*
bool checkBit(int n, int i) { return (n&(1<<i)); }
int setBit(int n, int i) { return (n|(1<<i)); }
int resetBit(int n, int i) { return (n&(~(1<<i))); }
*/
//end of template

#define MX 100007
#define MXN 407
#define MXE 200007

int source, sink, NN, n, m;
int Q[MXN], fin[MXN], pro[MXN], dist[MXN], nEdge;
int flow[MXE], cap[MXE], nex[MXE], to[MXE];

void init()
{
	//src = _src, snk = _snk, nNode = _n, nEdge = 0;
	for(int i = 0; i <= NN; i ++) fin[i] = -1;
	nEdge = 0;
}

void addEdge(int u, int v, int c)
{
	to[ nEdge ] = v; cap[ nEdge ] = c; flow[ nEdge ] = 0; nex[ nEdge ] = fin[ u ]; fin[ u ] = nEdge ++;
	to[ nEdge ] = u; cap[ nEdge ] = 0; flow[ nEdge ] = 0; nex[ nEdge ] = fin[ v ]; fin[ v ] = nEdge ++;
}

bool bfs()
{ int st, en;

	for(int i = 0; i <= NN; i ++) dist[i] = -1;

	dist[source] = st = en = 0;

	Q[ en ++ ] = source;

	while(st < en) {

		int u = Q[ st ++ ];

		for(int i = fin[u]; i >= 0; i = nex[ i ]) {

			int v = to[ i ];
			if(flow[i] < cap[i] && dist[v] == -1) {

				dist[v] = dist[u] + 1;
				Q[ en ++ ] = v;
			}
		}
	}

	return dist[sink] != -1;
}

int dfs(int u, int fl)
{
	if(u == sink) return fl;

	for(int &i = pro[ u ]; i >= 0; i = nex[ i ]) {

		int v = to[ i ];

		if(flow[i] < cap[i] && dist[v] == dist[u] + 1) {

			int df = dfs(v, min(cap[ i ] - flow[ i ], fl) );

			if(df > 0) {

				flow[i] += df;
				flow[i ^ 1] -= df;

				return df;
			}
		}
	}
	return 0;
}

int dinic()
{
	int ret = 0;

	for(int i = 0; i < nEdge; i ++) flow[i] = 0;

	while( bfs() ) {

		for(int i = 0; i <= NN; i ++) pro[i] = fin[i];

		while(true) {

			int df = dfs(source, inf);
			if(df) ret += df;
			else break;
		}
	}
	return ret;
}

int a[MX];
vector<int> ans[MX];
int vis[MX], ed[300][300];

int main () {
#ifdef kfoozminus
//	freopen("in", "r", stdin);
//	freopen("out", "w", stdout);
#endif
	seive(200000);
	int odd = 0, even = 0, i, j;

	scanf("%d", &n);
	for(i = 0; i < n; i ++) {
		scanf("%d", &a[i]);
		if(a[i] & 1) odd ++;
		else even ++;
	}
	if(odd != even) {
		printf("Impossible\n");
		return 0;
	}

	source = 0;
	sink = n + 1;
	NN = sink;
	init();
	for(i = 0; i < n; i ++) {
		if(a[i] & 1) {
			addEdge(source, i + 1, 2);
		}
		else addEdge(i + 1, sink, 2);
		if(a[i] & 1) {
			for(j = 0; j < n; j ++) {
				if(isPrime(a[i] + a[j])) {
					addEdge(i + 1, j + 1, 1);
					//dbg(a[i] + a[j]);
				}
			}
		}
	}
	int p = dinic();
	dbg(p);
	int in = -1;
	if(p == 2 * even) {
		//printf("Possible\n");
		for(i = 1; i <= n; i ++) {
			//while(true) {
				for(j = fin[i]; j >= 0; j = nex[j]) {
					if(cap[j] == 2) continue;
					if(cap[j] == 1 && flow[j] == 1) {
						ed[i][ to[j] ] = 1;
						ed[ to[j] ][i] = 1;
						dbg(i, to[j]);
						//i = to[j];
						//break;
					}
				}
			//}
		}
		for(i = 1; i <= n; i ++) {
			if(vis[i] == 0) in ++;
			while(vis[i] == 0) {
				vis[i] = 1;
				ans[in].PB(i);
				for(j = 1; j <= n; j ++) {
					if(vis[j]) continue;
					if(ed[i][j]) {
						i = j;
						break;
					}
				}
			}
		}
		printf("%d\n", in + 1);
		for(i = 0; i <= in; i ++) {
			printf("%d ", ans[i].size());
			for(auto it : ans[i]) printf("%d ", it);
			nl;
		}
	}
	else printf("Impossible\n");

//	timeStamp;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=210;
struct Edge{
	int to,cap,rev;
	Edge(int _to=0,int _cap=0,int _rev=0):to(_to),cap(_cap),rev(_rev){}
};
vector<Edge> g[maxn];
int level[maxn],iter[maxn];
inline void add_edge(int u,int v,int cap){
	g[u].push_back(Edge(v,cap,(int)g[v].size()));
	g[v].push_back(Edge(u,0,(int)g[u].size()-1));
}
bool bfs(int source,int sink){
	memset(level,-1,sizeof level);
	memset(iter,0,sizeof iter);
	queue<int> q;
	q.push(source);
	level[source]=0;
	while(!q.empty()){
		int from=q.front();
		q.pop();
		for(int i=0;i<(int)g[from].size();i++){
			Edge& e=g[from][i];
			if(e.cap>0 && level[e.to]==-1){
				level[e.to]=level[from]+1;
				q.push(e.to);
			}
		}
	}
	return level[sink]!=-1;
}
int find_flow(int from,int sink,int max_flow){
	if(from==sink) return max_flow;
	for(int& i=iter[from];i<(int)g[from].size();i++){
		Edge& e=g[from][i];
		if(e.cap>0 && level[e.to]>level[from]){
			int f=find_flow(e.to,sink,min(max_flow,e.cap));
			if(f>0){
				e.cap-=f;
				g[e.to][e.rev].cap+=f;
				return f;
			}
		}
	}
	return 0;
}
inline int find_max_flow(int source,int sink){
	int max_flow=0,flow;
	while(bfs(source,sink)){
		while((flow=find_flow(source,sink,0x3f3f3f3f))>0)
			max_flow+=flow;
	}
	return max_flow;
}
bool notPrime[20010];
vector<int> prime;
void sieve(){
	notPrime[0]=notPrime[1]=true;
	for(int i=2;i<=20000;i++){
		if(!notPrime[i]) prime.push_back(i);
		for(int j=0;j<(int)prime.size() && (ll)prime[j]*i<=20000;j++){
			int d=prime[j]*i;
			notPrime[d]=true;
			if(i%prime[j]==0) break;
		}
	}
}
int a[210],pre[210],nxt[210];
bool vis[210];
vector<int> ans[210];
int ans_size;
int n;
void get_ans(int from){
	ans_size++;
	while(!vis[from]){
		ans[ans_size].push_back(from);
		vis[from]=true;
		for(int i=0;i<(int)g[from].size();i++){
			Edge& e=g[from][i];
			if(1<=e.to && e.to<=n && (a[from]&1)!=(a[e.to]&1) && !vis[e.to]){
				if((a[from]&1) && e.cap==1){
					from=e.to;
					break;
				}else if((a[from]%2==0) && e.cap==0){
					from=e.to;
					break;
				}
			}
		}
	}
}
int main(){
	sieve();
	scanf("%d",&n);
	int source=0,sink=n+1;
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	for(int i=1;i<=n;i++){
		if(a[i]&1) add_edge(i,sink,2);
		else{
			add_edge(source,i,2);
			for(int j=1;j<=n;j++)
				if(a[j]&1)
					add_edge(i,j,1);
		}
	}
	if(find_max_flow(source,sink)!=n) puts("Impossible"),exit(0);
	for(int i=1;i<=n;i++)
		if(!vis[i])
			get_ans(i);
	printf("%d\n",ans_size);
	for(int i=1;i<=ans_size;i++){
		printf("%d ",(int)ans[i].size());
		for(int j=0;j<(int)ans[i].size();j++)
			printf("%d ",ans[i][j]);
		puts("");
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=210;
struct Edge{
	int to,cap,rev;
	Edge(int _to=0,int _cap=0,int _rev=0):to(_to),cap(_cap),rev(_rev){}
};
vector<Edge> g[maxn];
int level[maxn],iter[maxn];
inline void add_edge(int u,int v,int cap){
	g[u].push_back(Edge(v,cap,(int)g[v].size()));
	g[v].push_back(Edge(u,0,(int)g[u].size()-1));
}
bool bfs(int source,int sink){
	memset(level,-1,sizeof level);
	memset(iter,0,sizeof iter);
	queue<int> q;
	q.push(source);
	level[source]=0;
	while(!q.empty()){
		int from=q.front();
		q.pop();
		for(int i=0;i<(int)g[from].size();i++){
			Edge& e=g[from][i];
			if(e.cap>0 && level[e.to]==-1){
				level[e.to]=level[from]+1;
				q.push(e.to);
			}
		}
	}
	return level[sink]!=-1;
}
int find_flow(int from,int sink,int max_flow){
	if(from==sink) return max_flow;
	for(int& i=iter[from];i<(int)g[from].size();i++){
		Edge& e=g[from][i];
		if(e.cap>0 && level[e.to]>level[from]){
			int f=find_flow(e.to,sink,min(max_flow,e.cap));
			if(f>0){
				e.cap-=f;
				g[e.to][e.rev].cap+=f;
				return f;
			}
		}
	}
	return 0;
}
inline int find_max_flow(int source,int sink){
	int max_flow=0,flow;
	while(bfs(source,sink)){
		while((flow=find_flow(source,sink,0x3f3f3f3f))>0)
			max_flow+=flow;
	}
	return max_flow;
}
bool notPrime[20010];
vector<int> prime;
void sieve(){
	notPrime[0]=notPrime[1]=true;
	for(int i=2;i<=20000;i++){
		if(!notPrime[i]) prime.push_back(i);
		for(int j=0;j<(int)prime.size() && (ll)prime[j]*i<=20000;j++){
			int d=prime[j]*i;
			notPrime[d]=true;
			if(i%prime[j]==0) break;
		}
	}
}
int a[210],pre[210],nxt[210];
bool vis[210];
vector<int> ans[210];
int ans_size;
int n;
void get_ans(int from){
	ans_size++;
	while(!vis[from]){
		ans[ans_size].push_back(from);
		vis[from]=true;
		for(int i=0;i<(int)g[from].size();i++){
			Edge& e=g[from][i];
			if(1<=e.to && e.to<=n && (a[from]&1)!=(a[e.to]&1) && !vis[e.to]){
				if((a[from]&1) && e.cap==1){
					from=e.to;
					break;
				}else if((a[from]%2==0) && e.cap==0){
					from=e.to;
					break;
				}
			}
		}
	}
}
int main(){
	sieve();
	scanf("%d",&n);
	int source=0,sink=n+1;
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	for(int i=1;i<=n;i++){
		if(a[i]&1) add_edge(i,sink,2);
		else{
			add_edge(source,i,2);
			for(int j=1;j<=n;j++)
				if(a[j]&1 && !notPrime[a[j]+a[i]])
					add_edge(i,j,1);
		}
	}
	if(find_max_flow(source,sink)!=n) puts("Impossible"),exit(0);
	for(int i=1;i<=n;i++)
		if(!vis[i])
			get_ans(i);
	printf("%d\n",ans_size);
	for(int i=1;i<=ans_size;i++){
		printf("%d ",(int)ans[i].size());
		for(int j=0;j<(int)ans[i].size();j++)
			printf("%d ",ans[i][j]);
		puts("");
	}
	return 0;
}


#include <bits/stdc++.h>
#define MAX 1000005
#define ll long long
#define upperlimit 1000100
#define INF 1e18
#define eps 1e-8
#define endl '\n'
#define pcc pair<char,char>
#define pii pair<int,int>
#define pll pair<ll,ll>
#define tr(container,it) for(typeof(container.begin()) it=container.begin();it!=container.end();it++)
#define MOD 1000000007LL
#define slld(t) scanf("%lld",&t)
#define sd(t) scanf("%d",&t)
#define pd(t) printf("%d\n",t)
#define plld(t) printf("%lld\n",t)
#define mp(a,b) make_pair(a,b)
#define FF first
#define SS second
#define pb(x) push_back(x)
#define vi vector<int>
#define vll vector<ll>
#define clr(a) memset(a,0,sizeof(a))
#define debug(a) printf("check%d\n",a)
#define csl ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

ll gcd(ll n1,ll n2){
    if(n2==0)
        return n1;
    if(n1%n2==0)return n2;
    return gcd(n2,n1%n2);
}
ll powmod(ll base,ll exponent)
{
    if(exponent<0) exponent+=MOD-1;
    ll ans=1;
    while(exponent){
        if(exponent&1)ans=(ans*base)%MOD;
        base=(base*base)%MOD;
        exponent/=2;
    }
    return ans;
}
#include <cmath>
#include <vector>
#include <iostream>
#include <queue>

using namespace std;

typedef long long LL;

struct Edge {
  int from, to, cap, flow, index;
  Edge(int from, int to, int cap, int flow, int index) :
    from(from), to(to), cap(cap), flow(flow), index(index) {}
};

struct PushRelabel {
  int N;
  vector<vector<Edge> > G;
  vector<LL> excess;
  vector<int> dist, active, count;
  queue<int> Q;

  PushRelabel(int N) : N(N), G(N), excess(N), dist(N), active(N), count(2*N) {}

  void AddEdge(int from, int to, int cap) {
    G[from].push_back(Edge(from, to, cap, 0, G[to].size()));
    if (from == to) G[from].back().index++;
    G[to].push_back(Edge(to, from, 0, 0, G[from].size() - 1));
  }

  void Enqueue(int v) {
    if (!active[v] && excess[v] > 0) { active[v] = true; Q.push(v); }
  }

  void Push(Edge &e) {
    int amt = int(min(excess[e.from], LL(e.cap - e.flow)));
    if (dist[e.from] <= dist[e.to] || amt == 0) return;
    e.flow += amt;
    G[e.to][e.index].flow -= amt;
    excess[e.to] += amt;
    excess[e.from] -= amt;
    Enqueue(e.to);
  }

  void Gap(int k) {
    for (int v = 0; v < N; v++) {
      if (dist[v] < k) continue;
      count[dist[v]]--;
      dist[v] = max(dist[v], N+1);
      count[dist[v]]++;
      Enqueue(v);
    }
  }

  void Relabel(int v) {
    count[dist[v]]--;
    dist[v] = 2*N;
    for (int i = 0; i < G[v].size(); i++)
      if (G[v][i].cap - G[v][i].flow > 0)
    dist[v] = min(dist[v], dist[G[v][i].to] + 1);
    count[dist[v]]++;
    Enqueue(v);
  }

  void Discharge(int v) {
    for (int i = 0; excess[v] > 0 && i < G[v].size(); i++) Push(G[v][i]);
    if (excess[v] > 0) {
      if (count[dist[v]] == 1)
    Gap(dist[v]);
      else
    Relabel(v);
    }
  }

  LL GetMaxFlow(int s, int t) {
    count[0] = N-1;
    count[N] = 1;
    dist[s] = N;
    active[s] = active[t] = true;
    for (int i = 0; i < G[s].size(); i++) {
      excess[s] += G[s][i].cap;
      Push(G[s][i]);
    }

    while (!Q.empty()) {
      int v = Q.front();
      Q.pop();
      active[v] = false;
      Discharge(v);
    }

    LL totflow = 0;
    for (int i = 0; i < G[s].size(); i++) totflow += G[s][i].flow;
    return totflow;
  }
};
bool prime[MAX];
int arr[MAX];
vi v[MAX];
vi ans[MAX];
int an=1;
bool visited[MAX];
void DFS(int i)
{
    visited[i]=true;
    ans[an].pb(i);
    for(int x:v[i])
    {
        if(!visited[x])
        {
            DFS(x);
            return;
        }
    }
}
int main()
{
    for(int i=2;i<=20000;i++)
        prime[i]=true;
    for(int i=2;i<=20000;i++)
    {
        if(prime[i])
        for(int j=2*i;j<=20000;j+=i)
            prime[j]=false;
    }
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>arr[i];
    }
    PushRelabel pr(n+n+2);
    for(int i=1;i<=n;i++)
    {
        pr.AddEdge(0,i,2);
        pr.AddEdge(n+i,n+n+1,2);

        if(arr[i]&1)
            continue;
        for(int j=1;j<=n;j++)
            if(i!=j&&prime[arr[i]+arr[j]])
                pr.AddEdge(i,n+j,1);
    }
    if(pr.GetMaxFlow(0,n+n+1)==n)
    {
        for(int i=1;i<=n;i++)
        {
            for(auto e: pr.G[i])
            {
                if(e.flow==1)
                {
                    //if(i==19)
                      //  cout<<e.to-n<<endl;
                    v[i].pb(e.to-n);
                    v[e.to-n].pb(i);
                }
            }
        }
        for(int i=1;i<=n;i++)
            if(!visited[i])
            {
                DFS(i);
                an++;
            }
        cout<<an-1<<endl;
        for(int i=1;i<an;i++)
        {
            cout<<ans[i].size()<<" ";
            //for(int j=0;j<ans[i].size();j++)
              //  cout<<arr[ans[i][j]]+arr[ans[i][j+1]]<<endl;
            for(auto j:ans[i])
                cout<<j<<" ";
            cout<<endl;
        }
    }
    else cout<<"Impossible"<<endl;
}


#include <bits/stdc++.h>
#define MAX 1000005
#define ll long long
#define upperlimit 1000100
#define INF 1e18
#define eps 1e-8
#define endl '\n'
#define pcc pair<char,char>
#define pii pair<int,int>
#define pll pair<ll,ll>
#define tr(container,it) for(typeof(container.begin()) it=container.begin();it!=container.end();it++)
#define MOD 1000000007LL
#define slld(t) scanf("%lld",&t)
#define sd(t) scanf("%d",&t)
#define pd(t) printf("%d\n",t)
#define plld(t) printf("%lld\n",t)
#define mp(a,b) make_pair(a,b)
#define FF first
#define SS second
#define pb(x) push_back(x)
#define vi vector<int>
#define vll vector<ll>
#define clr(a) memset(a,0,sizeof(a))
#define debug(a) printf("check%d\n",a)
#define csl ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

ll gcd(ll n1,ll n2){
    if(n2==0)
        return n1;
    if(n1%n2==0)return n2;
    return gcd(n2,n1%n2);
}
ll powmod(ll base,ll exponent)
{
    if(exponent<0) exponent+=MOD-1;
    ll ans=1;
    while(exponent){
        if(exponent&1)ans=(ans*base)%MOD;
        base=(base*base)%MOD;
        exponent/=2;
    }
    return ans;
}
#include <cmath>
#include <vector>
#include <iostream>
#include <queue>

using namespace std;

typedef long long LL;

struct Edge {
  int from, to, cap, flow, index;
  Edge(int from, int to, int cap, int flow, int index) :
    from(from), to(to), cap(cap), flow(flow), index(index) {}
};

struct PushRelabel {
  int N;
  vector<vector<Edge> > G;
  vector<LL> excess;
  vector<int> dist, active, count;
  queue<int> Q;

  PushRelabel(int N) : N(N), G(N), excess(N), dist(N), active(N), count(2*N) {}

  void AddEdge(int from, int to, int cap) {
    G[from].push_back(Edge(from, to, cap, 0, G[to].size()));
    if (from == to) G[from].back().index++;
    G[to].push_back(Edge(to, from, 0, 0, G[from].size() - 1));
  }

  void Enqueue(int v) {
    if (!active[v] && excess[v] > 0) { active[v] = true; Q.push(v); }
  }

  void Push(Edge &e) {
    int amt = int(min(excess[e.from], LL(e.cap - e.flow)));
    if (dist[e.from] <= dist[e.to] || amt == 0) return;
    e.flow += amt;
    G[e.to][e.index].flow -= amt;
    excess[e.to] += amt;
    excess[e.from] -= amt;
    Enqueue(e.to);
  }

  void Gap(int k) {
    for (int v = 0; v < N; v++) {
      if (dist[v] < k) continue;
      count[dist[v]]--;
      dist[v] = max(dist[v], N+1);
      count[dist[v]]++;
      Enqueue(v);
    }
  }

  void Relabel(int v) {
    count[dist[v]]--;
    dist[v] = 2*N;
    for (int i = 0; i < G[v].size(); i++)
      if (G[v][i].cap - G[v][i].flow > 0)
    dist[v] = min(dist[v], dist[G[v][i].to] + 1);
    count[dist[v]]++;
    Enqueue(v);
  }

  void Discharge(int v) {
    for (int i = 0; excess[v] > 0 && i < G[v].size(); i++) Push(G[v][i]);
    if (excess[v] > 0) {
      if (count[dist[v]] == 1)
    Gap(dist[v]);
      else
    Relabel(v);
    }
  }

  LL GetMaxFlow(int s, int t) {
    count[0] = N-1;
    count[N] = 1;
    dist[s] = N;
    active[s] = active[t] = true;
    for (int i = 0; i < G[s].size(); i++) {
      excess[s] += G[s][i].cap;
      Push(G[s][i]);
    }

    while (!Q.empty()) {
      int v = Q.front();
      Q.pop();
      active[v] = false;
      Discharge(v);
    }

    LL totflow = 0;
    for (int i = 0; i < G[s].size(); i++) totflow += G[s][i].flow;
    return totflow;
  }
};
bool prime[MAX];
int arr[MAX];
vi v[MAX];
vi ans[MAX];
int an=1;
bool visited[MAX];
void DFS(int i)
{
    visited[i]=true;
    ans[an].pb(i);
    for(int x:v[i])
    {
        if(!visited[x])
        {
            DFS(x);
            return;
        }
    }
}
int main()
{
    for(int i=2;i<=10000;i++)
        prime[i]=true;
    for(int i=2;i<=10000;i++)
    {
        if(prime[i])
        for(int j=2*i;j<=10000;j+=i)
            prime[j]=false;
    }
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>arr[i];
    }
    PushRelabel pr(n+n+2);
    for(int i=1;i<=n;i++)
    {
        pr.AddEdge(0,i,2);
        pr.AddEdge(n+i,n+n+1,2);

        if(arr[i]&1)
            continue;
        for(int j=1;j<=n;j++)
            if(i!=j&&prime[arr[i]+arr[j]])
                pr.AddEdge(i,n+j,1);
    }
    if(pr.GetMaxFlow(0,n+n+1)==n)
    {
        for(int i=1;i<=n;i++)
        {
            for(auto e: pr.G[i])
            {
                if(e.flow==1)
                {
                    //if(i==19)
                      //  cout<<e.to-n<<endl;
                    v[i].pb(e.to-n);
                    v[e.to-n].pb(i);
                }
            }
        }
        for(int i=1;i<=n;i++)
            if(!visited[i])
            {
                DFS(i);
                an++;
            }
        cout<<an-1<<endl;
        for(int i=1;i<an;i++)
        {
            cout<<ans[i].size()<<" ";
            //for(int j=0;j<ans[i].size();j++)
              //  cout<<arr[ans[i][j]]+arr[ans[i][j+1]]<<endl;
            for(auto j:ans[i])
                cout<<j<<" ";
            cout<<endl;
        }
    }
    else cout<<"Impossible"<<endl;
}


#include <bits/stdc++.h>
#define MAX 1000005
#define ll long long
#define upperlimit 1000100
#define INF 1e18
#define eps 1e-8
#define endl '\n'
#define pcc pair<char,char>
#define pii pair<int,int>
#define pll pair<ll,ll>
#define tr(container,it) for(typeof(container.begin()) it=container.begin();it!=container.end();it++)
#define MOD 1000000007LL
#define slld(t) scanf("%lld",&t)
#define sd(t) scanf("%d",&t)
#define pd(t) printf("%d\n",t)
#define plld(t) printf("%lld\n",t)
#define mp(a,b) make_pair(a,b)
#define FF first
#define SS second
#define pb(x) push_back(x)
#define vi vector<int>
#define vll vector<ll>
#define clr(a) memset(a,0,sizeof(a))
#define debug(a) printf("check%d\n",a)
#define csl ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

ll gcd(ll n1,ll n2){
    if(n2==0)
        return n1;
    if(n1%n2==0)return n2;
    return gcd(n2,n1%n2);
}
ll powmod(ll base,ll exponent)
{
    if(exponent<0) exponent+=MOD-1;
    ll ans=1;
    while(exponent){
        if(exponent&1)ans=(ans*base)%MOD;
        base=(base*base)%MOD;
        exponent/=2;
    }
    return ans;
}
#include <cmath>
#include <vector>
#include <iostream>
#include <queue>

using namespace std;

typedef long long LL;

struct Edge {
  int from, to, cap, flow, index;
  Edge(int from, int to, int cap, int flow, int index) :
    from(from), to(to), cap(cap), flow(flow), index(index) {}
};

struct PushRelabel {
  int N;
  vector<vector<Edge> > G;
  vector<LL> excess;
  vector<int> dist, active, count;
  queue<int> Q;

  PushRelabel(int N) : N(N), G(N), excess(N), dist(N), active(N), count(2*N) {}

  void AddEdge(int from, int to, int cap) {
    G[from].push_back(Edge(from, to, cap, 0, G[to].size()));
    if (from == to) G[from].back().index++;
    G[to].push_back(Edge(to, from, 0, 0, G[from].size() - 1));
  }

  void Enqueue(int v) {
    if (!active[v] && excess[v] > 0) { active[v] = true; Q.push(v); }
  }

  void Push(Edge &e) {
    int amt = int(min(excess[e.from], LL(e.cap - e.flow)));
    if (dist[e.from] <= dist[e.to] || amt == 0) return;
    e.flow += amt;
    G[e.to][e.index].flow -= amt;
    excess[e.to] += amt;
    excess[e.from] -= amt;
    Enqueue(e.to);
  }

  void Gap(int k) {
    for (int v = 0; v < N; v++) {
      if (dist[v] < k) continue;
      count[dist[v]]--;
      dist[v] = max(dist[v], N+1);
      count[dist[v]]++;
      Enqueue(v);
    }
  }

  void Relabel(int v) {
    count[dist[v]]--;
    dist[v] = 2*N;
    for (int i = 0; i < G[v].size(); i++)
      if (G[v][i].cap - G[v][i].flow > 0)
    dist[v] = min(dist[v], dist[G[v][i].to] + 1);
    count[dist[v]]++;
    Enqueue(v);
  }

  void Discharge(int v) {
    for (int i = 0; excess[v] > 0 && i < G[v].size(); i++) Push(G[v][i]);
    if (excess[v] > 0) {
      if (count[dist[v]] == 1)
    Gap(dist[v]);
      else
    Relabel(v);
    }
  }

  LL GetMaxFlow(int s, int t) {
    count[0] = N-1;
    count[N] = 1;
    dist[s] = N;
    active[s] = active[t] = true;
    for (int i = 0; i < G[s].size(); i++) {
      excess[s] += G[s][i].cap;
      Push(G[s][i]);
    }

    while (!Q.empty()) {
      int v = Q.front();
      Q.pop();
      active[v] = false;
      Discharge(v);
    }

    LL totflow = 0;
    for (int i = 0; i < G[s].size(); i++) totflow += G[s][i].flow;
    return totflow;
  }
};
bool prime[MAX];
int arr[MAX];
vi v[MAX];
vi ans[MAX];
int an=1;
bool visited[MAX];
void DFS(int i)
{
    if(visited[i])
        return;
    visited[i]=true;
    ans[an].pb(i);
    for(int x:v[i])
        DFS(x);
}
int main()
{
    for(int i=2;i<=10000;i++)
        prime[i]=true;
    for(int i=2;i<=10000;i++)
    {
        if(prime[i])
        for(int j=2*i;j<=10000;j+=i)
            prime[j]=false;
    }
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>arr[i];
    }
    PushRelabel pr(n+n+2);
    for(int i=1;i<=n;i++)
    {
        pr.AddEdge(0,i,2);
        pr.AddEdge(n+i,n+n+1,2);
        for(int j=1;j<=n;j++)
            if(i!=j&&prime[arr[i]+arr[j]])
                pr.AddEdge(i,n+j,1);
    }
    if(pr.GetMaxFlow(0,n+n+1)==2*n)
    {
        for(int i=1;i<=n;i++)
        {
            for(auto e: pr.G[i])
            {
                if(e.flow==1)
                {
                    //if(i==2)
                      //  cout<<e.to-n<<endl;
                    v[i].pb(e.to-n);
                }
            }
        }
        for(int i=1;i<=n;i++)
            if(!visited[i])
            {
                DFS(i);
                an++;
            }
        cout<<an-1<<endl;
        for(int i=1;i<an;i++)
        {
            cout<<ans[i].size()<<" ";
            for(auto j:ans[i])
                cout<<j<<" ";
            cout<<endl;
        }
    }
    else cout<<"Impossible"<<endl;
}


//dont worry about duplicate edges
//dont worry about self loops
#include<bits/stdc++.h>
#define ll long long

#define nl printf("\n")
#define pb(x) push_back(x)

#define S(a) scanf("%d",&a)
#define S2(a,b) scanf("%d%d",&a,&b)
#define S3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define P(a) printf("%d",a)

#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)

#define PL(a) printf("%lld",a)
#define PLN(a) printf("%lld\n",a)
#define PLC(a) printf("%lld ",a)
#define SL(a) scanf("%lld",&a)
#define SL2(a,b) scanf("%lld%lld",&a,&b)
#define SL3(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
#define SL4(a,b,c,d) scanf("%lld%lld%lld%lld",&a,&b,&c,&d)

#define CLR(a) memset(a,0,sizeof(a))
#define SET(a) memset(a,-1,sizeof(a))
#define FOOL(a) memset(a,false,sizeof(a))
#define fr(i,a,n) for(i=a;i<=n;i++)
#define frv(i,v) for(i=0;i<(int)v.size();i++)
#define pi acos(-1.0)
#define po 1000000
#define co 1000000
#define mod 786433
#define MAXN 400
#define INF 100000000
using namespace std;

struct edge
{
    ll a, b, cap, flow;
};

ll s, t, d[MAXN], ptr[MAXN], q[MAXN];
vector<edge> e;
vector<ll> g[MAXN],p;
void add_edge (ll a, ll b, ll cap) {
    edge e1 = { a, b, cap, 0 };
    edge e2 = { b, a, 0, 0 };
    g[a].pb((int) e.size());
    e.pb (e1);
    g[b].pb((int) e.size());
    e.pb (e2);
}

bool bfs() //d->level   //q->queue //g[v][i]->index of e for an edge from v
{
    ll qh=0,i, qt=0,v,id,to;
    q[qt++] = s;
    SET(d);
    d[s] = 0;
    while (qh < qt && d[t] == -1)
    {
        v = q[qh++];
        frv(i,g[v])
        {
            id = g[v][i],
            to = e[id].b;
            if (d[to] == -1 && e[id].flow < e[id].cap)
            {
                q[qt++] = to;
                d[to] = d[v] + 1;
            }
        }
    }
    return d[t] != -1;
}

ll dfs (ll v, ll flow) {
    ll id,to,pushed;
    if (!flow)  return 0;
    if (v == t)  return flow;
    for (; ptr[v]<(int)g[v].size(); ++ptr[v]) {
        id = g[v][ptr[v]],
        to = e[id].b;
        if (d[to] != d[v] + 1)  continue;
        pushed = dfs (to, min (flow, e[id].cap - e[id].flow));
        if (pushed)
        {
            e[id].flow += pushed;
            e[id^1].flow -= pushed;
            return pushed;
        }
    }
    return 0;
}

ll dinic()
{
    ll flow = 0,pushed;
    for (;;)
    {
        if (!bfs())  break;
        CLR(ptr);
        while (1)
        {
            pushed = dfs (s, INF);
            if(!pushed)break;
            flow += pushed;
        }
    }
    return flow;
}

set<ll> ss[10001];
vector<ll> ans[10001];
bool prime[50000];
ll a[4000];
void gg(ll x,ll i)
{
    ans[i].pb(x);
    while(!ss[x].empty())
    {
        ll y=*ss[x].begin();
        ss[y].erase(x),ss[x].erase(y);
        ans[i].pb(y);
        x=y;
    }
}
int main()
{
//  add_edge(mapp[i],j+1,1);
//  PLN(dinic());
    ll i,j;
    memset(prime,1,sizeof(prime));
    for(i=2;i*i<50000;i++)
        if(prime[i])
            for(j=i*i;j<50000;j+=i)
                prime[j]=0;
    prime[0]=prime[1]=0;
    ll n,x;
    SL(n);

    s=0;t=n+1;
    fr(i,1,n)
    {
        SL(x);a[i]=x;
        if(x%2==0)add_edge(s,i,2);
        else add_edge(i,t,2);
    }

    fr(i,1,n)
        fr(j,1,n)
            if(prime[a[i]+a[j]])
            {
                if(a[i]%2==0)add_edge(i,j,1);
                else add_edge(j,i,1);
            }
    j=dinic();
    if(n%2==0 and j==n)
    {
        for(edge ee:e)
            if(ee.a>0 and ee.a<=n and ee.b!=0 and ee.b<=n and a[ee.a]%2==0 and a[ee.b]%2!=0 and ee.flow==1)
                ss[ee.a].insert(ee.b),ss[ee.b].insert(ee.a);
        ll pans=0;
        fr(i,1,n)
            if(!ss[i].empty())gg(i,pans),pans++;
        PLN(pans);
        fr(i,0,pans-1)
        {
            ans[i].pop_back();
            PLC(ans[i].size());
            for(auto xxx:ans[i])
                PLC(xxx);
            nl;
        }
    }
    else printf("Impossible\n");
}


//dont worry about duplicate edges
//dont worry about self loops
#include<bits/stdc++.h>
#define ll long long

#define nl printf("\n")
#define pb(x) push_back(x)

#define S(a) scanf("%d",&a)
#define S2(a,b) scanf("%d%d",&a,&b)
#define S3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define P(a) printf("%d",a)

#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)

#define PL(a) printf("%lld",a)
#define PLN(a) printf("%lld\n",a)
#define PLC(a) printf("%lld ",a)
#define SL(a) scanf("%lld",&a)
#define SL2(a,b) scanf("%lld%lld",&a,&b)
#define SL3(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
#define SL4(a,b,c,d) scanf("%lld%lld%lld%lld",&a,&b,&c,&d)

#define CLR(a) memset(a,0,sizeof(a))
#define SET(a) memset(a,-1,sizeof(a))
#define FOOL(a) memset(a,false,sizeof(a))
#define fr(i,a,n) for(i=a;i<=n;i++)
#define frv(i,v) for(i=0;i<(int)v.size();i++)
#define pi acos(-1.0)
#define po 1000000
#define co 1000000
#define mod 786433
#define MAXN 400
#define INF 100000000
using namespace std;

struct edge
{
    ll a, b, cap, flow;
};

ll s, t, d[MAXN], ptr[MAXN], q[MAXN];
vector<edge> e;
vector<ll> g[MAXN],p;
void add_edge (ll a, ll b, ll cap) {
    edge e1 = { a, b, cap, 0 };
    edge e2 = { b, a, 0, 0 };
    g[a].pb((int) e.size());
    e.pb (e1);
    g[b].pb((int) e.size());
    e.pb (e2);
}

bool bfs() //d->level   //q->queue //g[v][i]->index of e for an edge from v
{
    ll qh=0,i, qt=0,v,id,to;
    q[qt++] = s;
    SET(d);
    d[s] = 0;
    while (qh < qt && d[t] == -1)
    {
        v = q[qh++];
        frv(i,g[v])
        {
            id = g[v][i],
            to = e[id].b;
            if (d[to] == -1 && e[id].flow < e[id].cap)
            {
                q[qt++] = to;
                d[to] = d[v] + 1;
            }
        }
    }
    return d[t] != -1;
}

ll dfs (ll v, ll flow) {
    ll id,to,pushed;
    if (!flow)  return 0;
    if (v == t)  return flow;
    for (; ptr[v]<(int)g[v].size(); ++ptr[v]) {
        id = g[v][ptr[v]],
        to = e[id].b;
        if (d[to] != d[v] + 1)  continue;
        pushed = dfs (to, min (flow, e[id].cap - e[id].flow));
        if (pushed)
        {
            e[id].flow += pushed;
            e[id^1].flow -= pushed;
            return pushed;
        }
    }
    return 0;
}

ll dinic()
{
    ll flow = 0,pushed;
    for (;;)
    {
        if (!bfs())  break;
        CLR(ptr);
        while (1)
        {
            pushed = dfs (s, INF);
            if(!pushed)break;
            flow += pushed;
        }
    }
    return flow;
}

vector<ll> v1,v2;
set<ll> ss[10001];
vector<ll> ans[10001];
set<ll> idx[10001];
bool prime[50000];
void gg(ll x,ll i)
{
    ans[i].pb(x);
    while(!ss[x].empty())
    {
        ll y=*ss[x].begin();
        ss[y].erase(x),ss[x].erase(y);
        ans[i].pb(y);
        x=y;
    }
}
int main()
{
//  add_edge(mapp[i],j+1,1);
//  PLN(dinic());
    ll i,j;
    memset(prime,1,sizeof(prime));
    for(i=2;i*i<50000;i++)
        if(prime[i])
            for(j=i*i;j<50000;j+=i)
                prime[j]=0;
    prime[0]=prime[1]=0;
    ll n,x;
    SL(n);
    fr(i,1,n)
    {
        SL(x);
        if(x%2==0)v1.pb(x);
        else v2.pb(x);
        idx[x].insert(i);
    }
    ll n1=v1.size();ll n2=v2.size();
    s=0;t=n+1;
    fr(i,1,n1)add_edge(s,i,2);
    fr(i,1,n2)add_edge(i+n1,t,2);

    fr(i,1,n1)
        fr(j,1,n2)
            if(prime[v1[i-1]+v2[j-1]])
                add_edge(i,j+n1,1);
    j=dinic();
    if(n1==n2 and j==2*n1)
    {
        for(edge ee:e)
            if(ee.a<=n1 and ee.b>n1 and ee.flow==1)
                ss[v1[ee.a-1]].insert(v2[ee.b-n1-1]),ss[v2[ee.b-n1-1]].insert(v1[ee.a-1]);
        ll pans=0;
        fr(i,1,10000)
            if(!ss[i].empty())gg(i,pans),pans++;
        PLN(pans);
        fr(i,0,pans-1)
        {
            ans[i].pop_back();
            PLC(ans[i].size());
            for(auto xxx:ans[i])
                PLC(*idx[xxx].begin()),idx[xxx].erase(*idx[xxx].begin());
            nl;
        }
    }
    else printf("Impossible\n");
}


//dont worry about duplicate edges
//dont worry about self loops
#include<bits/stdc++.h>
#define ll long long

#define nl printf("\n")
#define pb(x) push_back(x)

#define S(a) scanf("%d",&a)
#define S2(a,b) scanf("%d%d",&a,&b)
#define S3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define P(a) printf("%d",a)

#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)

#define PL(a) printf("%lld",a)
#define PLN(a) printf("%lld\n",a)
#define PLC(a) printf("%lld ",a)
#define SL(a) scanf("%lld",&a)
#define SL2(a,b) scanf("%lld%lld",&a,&b)
#define SL3(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
#define SL4(a,b,c,d) scanf("%lld%lld%lld%lld",&a,&b,&c,&d)

#define CLR(a) memset(a,0,sizeof(a))
#define SET(a) memset(a,-1,sizeof(a))
#define FOOL(a) memset(a,false,sizeof(a))
#define fr(i,a,n) for(i=a;i<=n;i++)
#define frv(i,v) for(i=0;i<(int)v.size();i++)
#define pi acos(-1.0)
#define po 1000000
#define co 1000000
#define mod 786433
#define MAXN 400
#define INF 100000000
using namespace std;

struct edge
{
    ll a, b, cap, flow;
};

ll s, t, d[MAXN], ptr[MAXN], q[MAXN];
vector<edge> e;
vector<ll> g[MAXN],p;
void add_edge (ll a, ll b, ll cap) {
    edge e1 = { a, b, cap, 0 };
    edge e2 = { b, a, 0, 0 };
    g[a].pb((int) e.size());
    e.pb (e1);
    g[b].pb((int) e.size());
    e.pb (e2);
}

bool bfs() //d->level   //q->queue //g[v][i]->index of e for an edge from v
{
    ll qh=0,i, qt=0,v,id,to;
    q[qt++] = s;
    SET(d);
    d[s] = 0;
    while (qh < qt && d[t] == -1)
    {
        v = q[qh++];
        frv(i,g[v])
        {
            id = g[v][i],
            to = e[id].b;
            if (d[to] == -1 && e[id].flow < e[id].cap)
            {
                q[qt++] = to;
                d[to] = d[v] + 1;
            }
        }
    }
    return d[t] != -1;
}

ll dfs (ll v, ll flow) {
    ll id,to,pushed;
    if (!flow)  return 0;
    if (v == t)  return flow;
    for (; ptr[v]<(int)g[v].size(); ++ptr[v]) {
        id = g[v][ptr[v]],
        to = e[id].b;
        if (d[to] != d[v] + 1)  continue;
        pushed = dfs (to, min (flow, e[id].cap - e[id].flow));
        if (pushed)
        {
            e[id].flow += pushed;
            e[id^1].flow -= pushed;
            return pushed;
        }
    }
    return 0;
}

ll dinic()
{
    ll flow = 0,pushed;
    for (;;)
    {
        if (!bfs())  break;
        CLR(ptr);
        while (1)
        {
            pushed = dfs (s, INF);
            if(!pushed)break;
            flow += pushed;
        }
    }
    return flow;
}

vector<ll> v1,v2;
set<ll> ss[10001];
vector<ll> ans[10001];
bool prime[50000];
ll a[4000];
void gg(ll x,ll i)
{
    ans[i].pb(x);
    while(!ss[x].empty())
    {
        ll y=*ss[x].begin();
        ss[y].erase(x),ss[x].erase(y);
        ans[i].pb(y);
        x=y;
    }
}
int main()
{
//  add_edge(mapp[i],j+1,1);
//  PLN(dinic());
    ll i,j;
    memset(prime,1,sizeof(prime));
    for(i=2;i*i<50000;i++)
        if(prime[i])
            for(j=i*i;j<50000;j+=i)
                prime[j]=0;
    prime[0]=prime[1]=0;
    ll n,x;
    SL(n);
    fr(i,1,n)
    {
        SL(x);a[i]=x;
        if(x%2==0)v1.pb(i);
        else v2.pb(i);
    }
    ll n1=v1.size();ll n2=v2.size();
    s=0;t=n+1;
    fr(i,1,n1)add_edge(s,v1[i-1],2);
    fr(i,1,n2)add_edge(v2[i-1],t,2);

    fr(i,1,n)
        fr(j,1,n)
            if(prime[a[i]+a[j]])
                add_edge(i,j,1);
    j=dinic();
    if(n1==n2 and j==2*n1)
    {
        for(edge ee:e)
            if(a[ee.a]%2==0 and a[ee.b]%2!=0 and ee.flow==1)
                ss[ee.a].insert(ee.b),ss[ee.b].insert(ee.a);
        ll pans=0;
        fr(i,1,n)
            if(!ss[i].empty())gg(i,pans),pans++;
        PLN(pans);
        fr(i,0,pans-1)
        {
            ans[i].pop_back();
            PLC(ans[i].size());
            for(auto xxx:ans[i])
                PLC(xxx);
            nl;
        }
    }
    else printf("Impossible\n");
}


//dont worry about duplicate edges
//dont worry about self loops
#include<bits/stdc++.h>
#define ll long long

#define nl printf("\n")
#define pb(x) push_back(x)

#define S(a) scanf("%d",&a)
#define S2(a,b) scanf("%d%d",&a,&b)
#define S3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define P(a) printf("%d",a)

#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)

#define PL(a) printf("%lld",a)
#define PLN(a) printf("%lld\n",a)
#define PLC(a) printf("%lld ",a)
#define SL(a) scanf("%lld",&a)
#define SL2(a,b) scanf("%lld%lld",&a,&b)
#define SL3(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
#define SL4(a,b,c,d) scanf("%lld%lld%lld%lld",&a,&b,&c,&d)

#define CLR(a) memset(a,0,sizeof(a))
#define SET(a) memset(a,-1,sizeof(a))
#define FOOL(a) memset(a,false,sizeof(a))
#define fr(i,a,n) for(i=a;i<=n;i++)
#define frv(i,v) for(i=0;i<(int)v.size();i++)
#define pi acos(-1.0)
#define po 1000000
#define co 1000000
#define mod 786433
#define MAXN 400
#define INF 100000000
using namespace std;

struct edge
{
    ll a, b, cap, flow;
};

ll s, t, d[MAXN], ptr[MAXN], q[MAXN];
vector<edge> e;
vector<ll> g[MAXN],p;
void add_edge (ll a, ll b, ll cap) {
    edge e1 = { a, b, cap, 0 };
    edge e2 = { b, a, 0, 0 };
    g[a].pb((int) e.size());
    e.pb (e1);
    g[b].pb((int) e.size());
    e.pb (e2);
}

bool bfs() //d->level   //q->queue //g[v][i]->index of e for an edge from v
{
    ll qh=0,i, qt=0,v,id,to;
    q[qt++] = s;
    SET(d);
    d[s] = 0;
    while (qh < qt && d[t] == -1)
    {
        v = q[qh++];
        frv(i,g[v])
        {
            id = g[v][i],
            to = e[id].b;
            if (d[to] == -1 && e[id].flow < e[id].cap)
            {
                q[qt++] = to;
                d[to] = d[v] + 1;
            }
        }
    }
    return d[t] != -1;
}

ll dfs (ll v, ll flow) {
    ll id,to,pushed;
    if (!flow)  return 0;
    if (v == t)  return flow;
    for (; ptr[v]<(int)g[v].size(); ++ptr[v]) {
        id = g[v][ptr[v]],
        to = e[id].b;
        if (d[to] != d[v] + 1)  continue;
        pushed = dfs (to, min (flow, e[id].cap - e[id].flow));
        if (pushed)
        {
            e[id].flow += pushed;
            e[id^1].flow -= pushed;
            return pushed;
        }
    }
    return 0;
}

ll dinic()
{
    ll flow = 0,pushed;
    for (;;)
    {
        if (!bfs())  break;
        CLR(ptr);
        while (1)
        {
            pushed = dfs (s, INF);
            if(!pushed)break;
            flow += pushed;
        }
    }
    return flow;
}

vector<ll> v1,v2;
set<ll> ss[1001];
vector<ll> ans[1001];
set<ll> idx[1001];
bool prime[500];
void gg(ll x,ll i)
{
    ans[i].pb(x);
    while(!ss[x].empty())
    {
        ll y=*ss[x].begin();
        ss[y].erase(x),ss[x].erase(y);
        ans[i].pb(y);
        x=y;
    }
}
int main()
{
//  add_edge(mapp[i],j+1,1);
//  PLN(dinic());
    ll i,j;
    memset(prime,1,sizeof(prime));
    for(i=2;i*i<500;i++)
        if(prime[i])
            for(j=i*i;j<500;j+=i)
                prime[j]=0;
    prime[0]=prime[1]=0;
    ll n,x;
    SL(n);
    fr(i,1,n)
    {
        SL(x);
        if(x%2==0)v1.pb(x);
        else v2.pb(x);
        idx[x].insert(i);
    }
    ll n1=v1.size();ll n2=v2.size();
    s=0;t=n+1;
    fr(i,1,n1)add_edge(s,i,2);
    fr(i,1,n2)add_edge(i+n1,t,2);

    fr(i,1,n1)
        fr(j,1,n2)
            if(prime[v1[i-1]+v2[j-1]])
                add_edge(i,j+n1,1);
    j=dinic();
    if(n1==n2 and j==2*n1)
    {
        for(edge ee:e)
            if(ee.a<=n1 and ee.b>n1 and ee.flow==1)
                ss[v1[ee.a-1]].insert(v2[ee.b-n1-1]),ss[v2[ee.b-n1-1]].insert(v1[ee.a-1]);
        ll pans=0;
        fr(i,1,400)
            if(!ss[i].empty())gg(i,pans),pans++;
        PLN(pans);
        fr(i,0,pans-1)
        {
            ans[i].pop_back();
            PLC(ans[i].size());
            for(auto xxx:ans[i])
                PLC(*idx[xxx].begin()),idx[xxx].erase(*idx[xxx].begin());
            nl;
        }
    }
    else printf("Impossible\n");
}


//dont worry about duplicate edges
//dont worry about self loops
#include<bits/stdc++.h>
#define ll long long

#define nl printf("\n")
#define pb(x) push_back(x)

#define S(a) scanf("%d",&a)
#define S2(a,b) scanf("%d%d",&a,&b)
#define S3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define P(a) printf("%d",a)

#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)

#define PL(a) printf("%lld",a)
#define PLN(a) printf("%lld\n",a)
#define PLC(a) printf("%lld ",a)
#define SL(a) scanf("%lld",&a)
#define SL2(a,b) scanf("%lld%lld",&a,&b)
#define SL3(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
#define SL4(a,b,c,d) scanf("%lld%lld%lld%lld",&a,&b,&c,&d)

#define CLR(a) memset(a,0,sizeof(a))
#define SET(a) memset(a,-1,sizeof(a))
#define FOOL(a) memset(a,false,sizeof(a))
#define fr(i,a,n) for(i=a;i<=n;i++)
#define frv(i,v) for(i=0;i<(int)v.size();i++)
#define pi acos(-1.0)
#define po 1000000
#define co 1000000
#define mod 786433
#define MAXN 400
#define INF 100000000
using namespace std;

struct edge
{
    ll a, b, cap, flow;
};

ll s, t, d[MAXN], ptr[MAXN], q[MAXN];
vector<edge> e;
vector<ll> g[MAXN],p;
void add_edge (ll a, ll b, ll cap) {
    edge e1 = { a, b, cap, 0 };
    edge e2 = { b, a, 0, 0 };
    g[a].pb((int) e.size());
    e.pb (e1);
    g[b].pb((int) e.size());
    e.pb (e2);
}

bool bfs() //d->level   //q->queue //g[v][i]->index of e for an edge from v
{
    ll qh=0,i, qt=0,v,id,to;
    q[qt++] = s;
    SET(d);
    d[s] = 0;
    while (qh < qt && d[t] == -1)
    {
        v = q[qh++];
        frv(i,g[v])
        {
            id = g[v][i],
            to = e[id].b;
            if (d[to] == -1 && e[id].flow < e[id].cap)
            {
                q[qt++] = to;
                d[to] = d[v] + 1;
            }
        }
    }
    return d[t] != -1;
}

ll dfs (ll v, ll flow) {
    ll id,to,pushed;
    if (!flow)  return 0;
    if (v == t)  return flow;
    for (; ptr[v]<(int)g[v].size(); ++ptr[v]) {
        id = g[v][ptr[v]],
        to = e[id].b;
        if (d[to] != d[v] + 1)  continue;
        pushed = dfs (to, min (flow, e[id].cap - e[id].flow));
        if (pushed)
        {
            e[id].flow += pushed;
            e[id^1].flow -= pushed;
            return pushed;
        }
    }
    return 0;
}

ll dinic()
{
    ll flow = 0,pushed;
    for (;;)
    {
        if (!bfs())  break;
        CLR(ptr);
        while (1)
        {
            pushed = dfs (s, INF);
            if(!pushed)break;
            flow += pushed;
        }
    }
    return flow;
}

set<ll> ss[10001];
vector<ll> ans[10001];
bool prime[50000];
ll a[4000];
void gg(ll x,ll i)
{
    ans[i].pb(x);
    while(!ss[x].empty())
    {
        ll y=*ss[x].begin();
        ss[y].erase(x),ss[x].erase(y);
        ans[i].pb(y);
        x=y;
    }
}
int main()
{
//  add_edge(mapp[i],j+1,1);
//  PLN(dinic());
    ll i,j;
    memset(prime,1,sizeof(prime));
    for(i=2;i*i<50000;i++)
        if(prime[i])
            for(j=i*i;j<50000;j+=i)
                prime[j]=0;
    prime[0]=prime[1]=0;
    ll n,x;
    SL(n);

    s=0;t=n+1;
    fr(i,1,n)
    {
        SL(x);a[i]=x;
        if(x%2==0)add_edge(s,i,2);
        else add_edge(i,t,2);
    }

    fr(i,1,n)
        fr(j,i+1,n)
            if(prime[a[i]+a[j]])
            {
                if(a[i]%2==0)add_edge(i,j,1);
                else add_edge(j,i,1);
            }
    j=dinic();
    if(n%2==0 and j==n)
    {
        for(edge ee:e)
            if(ee.a>0 and ee.a<=n and ee.b!=0 and ee.b<=n and a[ee.a]%2==0 and a[ee.b]%2!=0 and ee.flow==1)
                ss[ee.a].insert(ee.b),ss[ee.b].insert(ee.a);
        ll pans=0;
        fr(i,1,n)
            if(!ss[i].empty())gg(i,pans),pans++;
        PLN(pans);
        fr(i,0,pans-1)
        {
            ans[i].pop_back();
            PLC(ans[i].size());
            for(auto xxx:ans[i])
                PLC(xxx);
            nl;
        }
    }
    else printf("Impossible\n");
}


#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;

#define pb push_back
#define pii pair<int, int>
#define mp make_pair
#define fi first
#define se second
#define llong long long
#define ullong unsigned long long
#define dlong long double

const int inf = 2*1e9 + 2018;

bool prime(int n) {
    for (int i=2; i*i<=n; i++)
        if (n%i==0)
            return 0;
    return 1;
}

struct edge{
    int a, b, cap, flow;
    edge(int a_, int b_, int cap_, int flow_): a(a_), b(b_), cap(cap_), flow(flow_) {}
};

vector<int> g[205];
vector<edge> e;
vector<int> ptr;
vector<int> d;
int s, t, N;

void add_edge(int a, int b, int cap) {
    g[a].pb((int) e.size());
    e.pb(edge(a, b, cap, 0));
    g[b].pb((int) e.size());
    e.pb(edge(b, a, 0, 0));
}

bool bfs() {
    d.assign(N, -1);
    queue<int> q;
    q.push(s);
    d[s] = 0;
    int v;
    while (!q.empty() && d[t]==-1) {
        v = q.front();
        for (int i=0; i<g[v].size(); i++) {
            int id = g[v][i];
            int to = e[id].b;
            if (d[to]==-1 && e[id].flow < e[id].cap) {
                d[to] = d[v] + 1;
                q.push(to);
            }
        }
        q.pop();
    }
    return (d[t]!=-1);
}

int dfs(int v, int flow) {
    if (!flow) return 0;
    if (v==t) return flow;
    for (; ptr[v]<g[v].size(); ptr[v]++) {
        int id = g[v][ptr[v]];
        int to = e[id].b;
        if (d[to] != d[v]+1) continue;
        int pushed = dfs(to, min(flow, e[id].cap - e[id].flow));
        if (pushed) {
            e[id].flow += pushed;
            e[id^1].flow -= pushed;
            return pushed;
        }
    }
    return 0;
}

int GetMaxFlow(int n, int _start_, int _end_) {
    N = n; s = _start_; t = _end_;
    int flow = 0;
    ptr.resize(n);
    while (1) {
        if (!bfs()) break;
        ptr.assign(N, 0);
        while (int pushed = dfs(s, inf))
            flow += pushed;
    }
    return flow;
}

vector<int> CircleG[205];
vector<int> comp;
vector<vector<int> > ans;
bool used[205];
void dfs_comp(int v) {
    used[v] = 1;
    comp.pb(v);
    for (int i=0; i<CircleG[v].size(); i++) {
        int to = CircleG[v][i];
        if (!used[to])
            dfs_comp(to);
    }
}

int main()
{
    ios_base::sync_with_stdio(false);
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);

    int n; cin >> n;
    int arr[200];
    vector<int> OddId, EvenId;
    for (int i=0; i<n; i++) {
        cin >> arr[i];
        if (arr[i]&1) OddId.pb(i);
        else EvenId.pb(i);
    }

    if (OddId.size() != EvenId.size()) {
        cout << "Impossible";
        return 0;
    }

    /// source -> n ||| sink -> n+1
    /// left -> odd ||| right -> even
    for (int i=0; i<OddId.size(); i++) add_edge(n, OddId[i], 2);
    for (int i=0; i<EvenId.size(); i++) add_edge(EvenId[i], n+1, 2);

    for (int i=0; i<OddId.size(); i++)
        for (int j=0; j<EvenId.size(); j++)
            if (prime(arr[OddId[i]] + arr[EvenId[j]]))
                add_edge(OddId[i], EvenId[j], 1);

    int MaxFlow = GetMaxFlow(n+2, n, n+1);
    if (MaxFlow != 2*OddId.size()) {
        cout << "Impossible";
        return 0;
    }

    /// --- --- --- recovers answer --- --- --- ///
    for (int i=0; i<e.size(); i++) {
        if (e[i].cap > 0 && e[i].flow == 1) {
            CircleG[e[i].a].pb(e[i].b);
            CircleG[e[i].b].pb(e[i].a);
        }
    }
    /// --- --- --- recovers answer --- --- --- ///

    for (int i=0; i<n; i++) used[i] = 0;
    for (int i=0; i<n; i++) {
        if (!used[i]) {
            comp.clear();
            dfs_comp(i);
            ans.pb(comp);
        }
    }

    cout << ans.size() << "\n";
    for (int i=0; i<ans.size(); i++) {
        cout << ans[i].size() << ' ';
        for (int j=0; j<ans[i].size(); j++)
            cout << ans[i][j]+1 << ' ';
        cout << "\n";
    }

    return 0;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;

#define pb push_back
#define pii pair<int, int>
#define mp make_pair
#define fi first
#define se second
#define llong long long
#define ullong unsigned long long
#define dlong long double

const int inf = 2*1e9 + 2018;

bool prime(int n) {
    for (int i=2; i*i<=n; i++)
        if (n%i==0)
            return 0;
    return 1;
}

struct edge{
    int a, b, cap, flow;
    edge(int a_, int b_, int cap_, int flow_): a(a_), b(b_), cap(cap_), flow(flow_) {}
};

vector<int> g[205];
vector<edge> e;
vector<int> ptr;
vector<int> d;
int s, t, N;

void add_edge(int a, int b, int cap) {
    g[a].pb((int) e.size());
    e.pb(edge(a, b, cap, 0));
    g[b].pb((int) e.size());
    e.pb(edge(b, a, 0, 0));
}

bool bfs() {
    d.assign(N, -1);
    queue<int> q;
    q.push(s);
    d[s] = 0;
    int v;
    while (!q.empty() && d[t]==-1) {
        v = q.front();
        for (int i=0; i<g[v].size(); i++) {
            int id = g[v][i];
            int to = e[id].b;
            if (d[to]==-1 && e[id].flow < e[id].cap) {
                d[to] = d[v] + 1;
                q.push(to);
            }
        }
        q.pop();
    }
    return (d[t]!=-1);
}

int dfs(int v, int flow) {
    if (!flow) return 0;
    if (v==t) return flow;
    for (; ptr[v]<g[v].size(); ptr[v]++) {
        int id = g[v][ptr[v]];
        int to = e[id].b;
        if (d[to] != d[v]+1) continue;
        int pushed = dfs(to, min(flow, e[id].cap - e[id].flow));
        if (pushed) {
            e[id].flow += pushed;
            e[id^1].flow -= pushed;
            return pushed;
        }
    }
    return 0;
}

int GetMaxFlow(int n, int _start_, int _end_) {
    N = n; s = _start_; t = _end_;
    int flow = 0;
    ptr.resize(n);
    while (1) {
        if (!bfs()) break;
        ptr.assign(N, 0);
        while (int pushed = dfs(s, inf))
            flow += pushed;
    }
    return flow;
}

vector<int> CircleG[205];
vector<int> comp;
vector<vector<int> > ans;
bool used[205];
void dfs_comp(int v) {
    used[v] = 1;
    comp.pb(v);
    for (int i=0; i<CircleG[v].size(); i++) {
        int to = CircleG[v][i];
        if (!used[to])
            dfs_comp(to);
    }
}

int main()
{
    ios_base::sync_with_stdio(false);
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);

    int n; cin >> n;
    int arr[200];
    vector<int> OddId, EvenId;
    for (int i=0; i<n; i++) {
        cin >> arr[i];
        if (arr[i]&1) OddId.pb(i);
        else EvenId.pb(i);
    }

    if (OddId.size() != EvenId.size()) {
        cout << "Impossible";
        return 0;
    }

    /// source -> n ||| sink -> n+1
    /// left -> odd ||| right -> even
    for (int i=0; i<OddId.size(); i++) add_edge(n, OddId[i], 2);
    for (int i=0; i<EvenId.size(); i++) add_edge(EvenId[i], n+1, 2);

    for (int i=0; i<OddId.size(); i++)
        for (int j=0; j<EvenId.size(); j++)
            if (prime(arr[OddId[i]] + arr[EvenId[j]]))
                add_edge(OddId[i], EvenId[j], 1);

    int MaxFlow = GetMaxFlow(n+2, n, n+1);
    if (MaxFlow != 2*OddId.size()) {
        cout << "Impossible";
        return 0;
    }

    /// --- --- --- recovers answer --- --- --- ///
    for (int i=0; i<e.size(); i++) {
        if (e[i].cap > 0 && e[i].flow == 1) {
            CircleG[e[i].a].pb(e[i].b);
            CircleG[e[i].b].pb(e[i].a);
        }
    }
    /// --- --- --- recovers answer --- --- --- ///

    for (int i=0; i<n; i++) used[i] = 0;
    for (int i=0; i<n; i++) {
        if (!used[i]) {
            comp.clear();
            dfs_comp(i);
            ans.pb(comp);
        }
    }

    cout << ans.size() << "\n";
    for (int i=0; i<ans.size(); i++) {
        cout << ans[i].size() << ' ';
        for (int j=0; j<ans[i].size(); j++)
            cout << ans[i][j]+1 << ' ';
        cout << "\n";
    }

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define MAXP 10010
bool isPrime[MAXP];
vector<int> primes;
int N;
int A[210];
void makePrime(){
    memset(isPrime, true, sizeof(isPrime));
    for(int i=2;i<MAXP;i++){
        if(isPrime[i])primes.push_back(i);
        for(int p : primes){
            if(i * p >= MAXP)break;
            isPrime[i * p] = false;
            if(i % p == 0)break;
        }
    }
}
struct Dinic{
	struct Edge{
		int v1, v2, f, c;
	};
	int N;
	vector<vector<int> >vc;
	vector<Edge> E;
	vector<int> dep;

	Dinic(int n=0): N(n), vc(vector<vector<int> >(N+1)), dep(vector<int>(N+1)) {}
	void add_edge(int a, int b, int c){
		vc[a].push_back(E.size());
		E.push_back({a, b, c, c});
		vc[b].push_back(E.size());
		E.push_back({b, a, 0, c});
	}
	int Bfs(int s, int t){
		fill(dep.begin(), dep.end(), -1);
		dep[s] = 0;
		queue<int> q;
		q.push(s);
		while(!q.empty()){
			int v = q.front(); q.pop();
			for(int i=0;i<(int)vc[v].size();i++){
				Edge e = E[vc[v][i]];
				if(e.f > 0 && dep[e.v2] == -1){
					dep[e.v2] = dep[v] + 1;
					q.push(e.v2);
				}
			}
		}
		return dep[t];
	}
	int Dfs(int x, int df, int t){
		if(x == t) return df;
		int res = 0;
		for(int i=0;i<(int)vc[x].size();i++){
			Edge &e = E[vc[x][i]];
			if(e.f > 0 && dep[e.v2] == dep[x] + 1){
				int f = Dfs(e.v2, min(df, e.f), t);
				e.f -= f; df -= f; res += f;
				E[vc[x][i] ^ 1].f += f;
				if(df == 0) return res;
			}
		}
		if(res == 0) dep[x] = -1;
		return res;
	}
	int Solve(int s, int t){
		int flow = 0;
		while(Bfs(s, t) != -1){
			flow += Dfs(s, 0x3f3f3f3f, t);
		}
		return flow;
	}
};
int main(){
    makePrime();
    scanf("%d", &N);
    int odd = 0, even = 0;
    int source = N, target = source + 1;
    Dinic d(N + 2);
    for(int i=0;i<N;i++){
        scanf("%d", &A[i]);
        if(A[i] & 1){
            d.add_edge(source, i, 2);
            odd++;
        }else{
            d.add_edge(i, target, 2);
            even++;
        }
    }
    for(int i=0;i<N;i++){
        for(int j=i+1;j<N;j++){
            if(isPrime[A[i] + A[j]]){
                if(A[i] & 1){
                    d.add_edge(i, j, 1);
                }else{
                    d.add_edge(j, i, 1);
                }
            }
        }
    }
    int flow = d.Solve(source, target);
    bool ans = flow == odd * 2 && even == odd;
    if(ans){
        vector<int> ed[210];
        bool vis[210] = {0};
        for(auto e : d.E){
            if(e.v1 != source && e.v1 != target && e.v2 != source && e.v2 != target && (A[e.v1] & 1) && e.f == 0){
                ed[e.v1].push_back(e.v2);
                ed[e.v2].push_back(e.v1);
            }
        }
        vector<vector<int>> ans;
        for(int i=0;i<N;i++){
            if(!vis[i]){
                int now = i;
                ans.push_back(vector<int>());
                while(!vis[now]){
                    vis[now] = true;
                    ans.back().push_back(now);
                    for(int j : ed[now]){
                        if(!vis[j]){
                            now = j;
                            break;
                        }
                    }
                }
            }
        }
        printf("%d\n", (int)ans.size());
        for(auto c : ans){
            printf("%d", (int)c.size());
            for(int x : c){
                printf(" %d", x + 1);
            }
            puts("");
        }
    }else{
        printf("Impossible\n");
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define MAXP 10010
bool isPrime[MAXP];
vector<int> primes;
int N;
int A[210];
void makePrime(){
    memset(isPrime, true, sizeof(isPrime));
    for(int i=2;i<MAXP;i++){
        if(isPrime[i])primes.push_back(i);
        for(int p : primes){
            if(i * p >= MAXP)break;
            isPrime[i * p] = false;
            if(i % p == 0)break;
        }
    }
}
struct Dinic{
	struct Edge{
		int v1, v2, f, c;
	};
	int N;
	vector<vector<int> >vc;
	vector<Edge> E;
	vector<int> dep;

	Dinic(int n=0): N(n), vc(vector<vector<int> >(N+1)), dep(vector<int>(N+1)) {}
	void add_edge(int a, int b, int c){
		vc[a].push_back(E.size());
		E.push_back({a, b, c, c});
		vc[b].push_back(E.size());
		E.push_back({b, a, 0, c});
	}
	int Bfs(int s, int t){
		fill(dep.begin(), dep.end(), -1);
		dep[s] = 0;
		queue<int> q;
		q.push(s);
		while(!q.empty()){
			int v = q.front(); q.pop();
			for(int i=0;i<(int)vc[v].size();i++){
				Edge e = E[vc[v][i]];
				if(e.f > 0 && dep[e.v2] == -1){
					dep[e.v2] = dep[v] + 1;
					q.push(e.v2);
				}
			}
		}
		return dep[t];
	}
	int Dfs(int x, int df, int t){
		if(x == t) return df;
		int res = 0;
		for(int i=0;i<(int)vc[x].size();i++){
			Edge &e = E[vc[x][i]];
			if(e.f > 0 && dep[e.v2] == dep[x] + 1){
				int f = Dfs(e.v2, min(df, e.f), t);
				e.f -= f; df -= f; res += f;
				E[vc[x][i] ^ 1].f += f;
				if(df == 0) return res;
			}
		}
		if(res == 0) dep[x] = -1;
		return res;
	}
	int Solve(int s, int t){
		int flow = 0;
		while(Bfs(s, t) != -1){
			flow += Dfs(s, 0x3f3f3f3f, t);
		}
		return flow;
	}
};
int main(){
    makePrime();
    scanf("%d", &N);
    int odd = 0, even = 0;
    int source = N, target = source + 1;
    Dinic d(N + 2);
    for(int i=0;i<N;i++){
        scanf("%d", &A[i]);
        if(A[i] & 1){
            d.add_edge(source, i, 2);
            odd++;
        }else{
            d.add_edge(i, target, 2);
            even++;
        }
    }
    for(int i=0;i<N;i++){
        for(int j=i+1;j<N;j++){
            if(isPrime[A[i] + A[j]]){
                if(A[i] & 1){
                    d.add_edge(i, j, 1);
                }else{
                    d.add_edge(j, i, 1);
                }
            }
        }
    }
    int flow = d.Solve(source, target);
    bool ans = flow == odd * 2 && even == odd;
    if(ans){
        vector<int> ed[210];
        bool vis[210] = {0};
        for(auto e : d.E){
            if(e.v1 != source && e.v1 != target && e.v2 != source && e.v2 != target && (A[e.v1] & 1) && e.f == 0){
                ed[e.v1].push_back(e.v2);
                ed[e.v2].push_back(e.v1);
            }
        }
        vector<vector<int>> ans;
        for(int i=0;i<N;i++){
            if(!vis[i]){
                ans.push_back(vector<int>());
                while(!vis[i]){
                    vis[i] = true;
                    ans.back().push_back(i);
                    for(int j : ed[i]){
                        if(!vis[j]){
                            i = j;
                            break;
                        }
                    }
                }
            }
        }
        printf("%d\n", (int)ans.size());
        for(auto c : ans){
            printf("%d", (int)c.size());
            for(int x : c){
                printf(" %d", x + 1);
            }
            puts("");
        }
    }else{
        printf("Impossible\n");
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define MAXP 20010
bool isPrime[MAXP];
vector<int> primes;
int N;
int A[210];
void makePrime(){
    memset(isPrime, true, sizeof(isPrime));
    for(int i=2;i<MAXP;i++){
        if(isPrime[i])primes.push_back(i);
        for(int p : primes){
            if(i * p >= MAXP)break;
            isPrime[i * p] = false;
            if(i % p == 0)break;
        }
    }
}
struct Dinic{
	struct Edge{
		int v1, v2, f, c;
	};
	int N;
	vector<vector<int> >vc;
	vector<Edge> E;
	vector<int> dep;

	Dinic(int n=0): N(n), vc(vector<vector<int> >(N+1)), dep(vector<int>(N+1)) {}
	void add_edge(int a, int b, int c){
		vc[a].push_back(E.size());
		E.push_back({a, b, c, c});
		vc[b].push_back(E.size());
		E.push_back({b, a, 0, c});
	}
	int Bfs(int s, int t){
		fill(dep.begin(), dep.end(), -1);
		dep[s] = 0;
		queue<int> q;
		q.push(s);
		while(!q.empty()){
			int v = q.front(); q.pop();
			for(int i=0;i<(int)vc[v].size();i++){
				Edge e = E[vc[v][i]];
				if(e.f > 0 && dep[e.v2] == -1){
					dep[e.v2] = dep[v] + 1;
					q.push(e.v2);
				}
			}
		}
		return dep[t];
	}
	int Dfs(int x, int df, int t){
		if(x == t) return df;
		int res = 0;
		for(int i=0;i<(int)vc[x].size();i++){
			Edge &e = E[vc[x][i]];
			if(e.f > 0 && dep[e.v2] == dep[x] + 1){
				int f = Dfs(e.v2, min(df, e.f), t);
				e.f -= f; df -= f; res += f;
				E[vc[x][i] ^ 1].f += f;
				if(df == 0) return res;
			}
		}
		if(res == 0) dep[x] = -1;
		return res;
	}
	int Solve(int s, int t){
		int flow = 0;
		while(Bfs(s, t) != -1){
			flow += Dfs(s, 0x3f3f3f3f, t);
		}
		return flow;
	}
};
int main(){
    makePrime();
    scanf("%d", &N);
    int odd = 0, even = 0;
    int source = N, target = source + 1;
    Dinic d(N + 2);
    for(int i=0;i<N;i++){
        scanf("%d", &A[i]);
        if(A[i] & 1){
            d.add_edge(source, i, 2);
            odd++;
        }else{
            d.add_edge(i, target, 2);
            even++;
        }
    }
    for(int i=0;i<N;i++){
        for(int j=i+1;j<N;j++){
            if(isPrime[A[i] + A[j]]){
                if(A[i] & 1){
                    d.add_edge(i, j, 1);
                }else{
                    d.add_edge(j, i, 1);
                }
            }
        }
    }
    int flow = d.Solve(source, target);
    bool ans = flow == odd * 2 && even == odd;
    if(ans){
        vector<int> ed[210];
        bool vis[210] = {0};
        for(auto e : d.E){
            if(e.v1 != source && e.v1 != target && e.v2 != source && e.v2 != target && (A[e.v1] & 1) && e.f == 0){
                ed[e.v1].push_back(e.v2);
                ed[e.v2].push_back(e.v1);
            }
        }
        vector<vector<int>> ans;
        for(int i=0;i<N;i++){
            if(!vis[i]){
                int now = i;
                ans.push_back(vector<int>());
                while(!vis[now]){
                    vis[now] = true;
                    ans.back().push_back(now);
                    for(int j : ed[now]){
                        if(!vis[j]){
                            now = j;
                            break;
                        }
                    }
                }
            }
        }
        printf("%d\n", (int)ans.size());
        for(auto c : ans){
            printf("%d", (int)c.size());
            for(int x : c){
                printf(" %d", x + 1);
            }
            puts("");
        }
    }else{
        printf("Impossible\n");
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std ;

#define ll long long
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define memf(a) memset(a,false,sizeof(a))
#define all(v) v.begin(),v.end()
#define sz(a) (ll)a.size()
#define F first
#define S second
#define INF 2000000000000000000
#define endl "\n"
#define _time_ 1.0 * clock() / CLOCKS_PER_SEC
#define popcount(x) __builtin_popcountll(x)
#define pll pair<ll,ll>
#define ld long double

const int M=1000000007;
const int MM=998244353;
const long double PI = acos(-1);

ll power(ll b,ll e,ll m)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b%m,e/2,m)%m;
    return power(b*b%m,e/2,m);
}
ll power( ll b, ll e)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b,e/2);
    return power(b*b,e/2);
}
template<typename T, typename U> static inline void amin(T &x, U y){ if(y<x) x=y; }
template<typename T, typename U> static inline void amax(T &x, U y){ if(x<y) x=y; }
template<typename T, typename U> ostream& operator<<(ostream &os, const pair<T, U> &p)
{
    return os<<'('<<p.F<< ","<<p.S<<')';
}

#define runSieve
const int N=1000005;
bool prime[N];
ll pf[N];
void sieve()
{
    int k=sqrt(N-2);
    for(int i=1;i<=N-2;++i)
        prime[i]=true;
    for(int i=2;i<=k;++i)
    {
        if(prime[i])
        {
            for(int k=i*i;k<=N-2;k+=i)
            {
                prime[k]=false;
                pf[k]=i;
            }
        }
    }
}

template<typename flow_t = long long>
struct Dinic {
    struct FlowEdge
    {
        int v, u;
        flow_t cap, flow = 0;
        FlowEdge(int v, int u, flow_t cap) : v(v), u(u), cap(cap) {}
    };
    const flow_t flow_inf = numeric_limits<flow_t>::max()/2;
    vector<FlowEdge> edges;
    vector<vector<int>> adj;
    int n, m = 0;
    int s, t;
    // s -> source
    // t -> sink
    vector<int> level, ptr;
    queue<int> q;

    Dinic(int n, int s, int t) : n(n), s(s), t(t)
    {
        adj.resize(n+1);
        level.resize(n+1);
        ptr.resize(n+1);
    }

    void add_edge(int v, int u, flow_t cap)
    {
        edges.emplace_back(v, u, cap);
        edges.emplace_back(u, v, 0);
        adj[v].push_back(m);
        adj[u].push_back(m + 1);
        m += 2;
    }

    bool bfs()
    {
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            for (int id : adj[v]) {
                if (edges[id].cap - edges[id].flow < 1)
                    continue;
                if (level[edges[id].u] != -1)
                    continue;
                level[edges[id].u] = level[v] + 1;
                q.push(edges[id].u);
            }
        }
        return level[t] != -1;
    }

    flow_t dfs(int v, flow_t pushed)
    {
        if (pushed == 0)
            return 0;
        if (v == t)
            return pushed;
        for (int& cid = ptr[v]; cid < (int)adj[v].size(); cid++) {
            int id = adj[v][cid];
            int u = edges[id].u;
            if (level[v] + 1 != level[u] || edges[id].cap - edges[id].flow < 1)
                continue;
            flow_t tr = dfs(u, min(pushed, edges[id].cap - edges[id].flow));
            if (tr == 0)
                continue;
            edges[id].flow += tr;
            edges[id ^ 1].flow -= tr;
            return tr;
        }
        return 0;
    }

    flow_t flow()
    {
        flow_t f = 0;
        while (true) {
            fill(level.begin(), level.end(), -1);
            level[s] = 0;
            q.push(s);
            if (!bfs())
                break;
            fill(ptr.begin(), ptr.end(), 0);
            while (flow_t pushed = dfs(s, flow_inf)) {
                f += pushed;
            }
        }
        return f;
    }
};
// .add_edge(u,v,cap);u->v
// .flow() == maxFlow

bitset<201> vis;
vector<int> g[201];

void dfs(int s,vector<int> &u)
{
    u.pb(s);
    vis[s] = true;
    for(auto &j:g[s])
    {
        if(!vis[j])
            dfs(j,u);
    }
}

int _runtimeTerror_()
{
    int n;
    cin>>n;
    vector<int> v(n+1);
    for(int i=1;i<=n;++i)
        cin>>v[i];
    Dinic<int> flow(n+2,0,n+1);
    vector<int> cnt(2,0);
    for(int i=1;i<=n;++i)
    {
        ++cnt[v[i]&1];
        if(v[i]&1)
            flow.add_edge(0,i,2);
        else
            flow.add_edge(i,n+1,2);
        for(int j=1;j<=n;++j)
        {
            if(v[i]%2 == 1 && v[j]%2 == 0 && prime[v[i]+v[j]])
                flow.add_edge(i,j,1);
        }
    }
    if(cnt[0] != cnt[1])
    {
        cout<<"Impossible\n";
        return 0;
    }
    int ans = flow.flow();
    if(ans == 2*cnt[0])
    {
        for(auto &k:flow.edges)
        {
            if(k.flow == 1)
                g[k.v].pb(k.u),g[k.u].pb(k.v);
        }
        vector<vector<int>> ans;
        for(int i=1;i<=n;++i)
        {
            if(!vis[i])
            {
                vector<int> u;
                dfs(i,u);
                ans.pb(u);
            }
        }
        cout<<sz(ans)<<"\n";
        for(auto &j:ans)
        {
            cout<<sz(j)<<" ";
            for(auto &k:j)
                cout<<k<<" ";
            cout<<"\n";
        }
    }
    else
    {
        cout<<"Impossible\n";
    }
    return 0;
}

int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    #ifdef runSieve
        sieve();
    #endif
    #ifdef NCR
        initialize();
    #endif
    int TESTS=1;
    //cin>>TESTS;
    while(TESTS--)
        _runtimeTerror_();
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
typedef long double ld;
const int maxn = (int)5e5 + 10;
const int mod = (int) 1e9 + 7;
const int inf = (1<<30) - 1;
int n;
int a[maxn];
int c[222][222];
int f[222][222];
int id[222];
int u[222];
int col[222];
int r[222];
int T;
int prime(int x) {
    for(int d = 2; d * d <= x; d++) {
        if(x %d == 0) return 0;
    }
    return 1;
}
bool dfs(int v) {
    if(v == n + 1) return 1;
    if(u[v] == T) return 0;
    u[v] = T;
    for(int i = 0; i <= n+1; i++) {
        if(c[v][i] > f[v][i] && dfs(i)) {
            f[v][i] ++;
            f[i][v] --;
            return 1;
        }
    }
    return 0;
}
vector<int> ord;
void dfs2(int v, int x) {
    col[v] = x;
    ord.emplace_back(r[v]);
    for(int i = 1; i <= n; i++) {
        if(col[i] == 0 && f[v][i] != 0) {
            dfs2(i, x);
        }
    }
}
void solve() {
    cin >> n;
    vector<int> e, o;
    for(int i=0; i < n; i++) {
        cin >> a[i];
        if(a[i] % 2 == 0) {
            e.emplace_back(a[i]);
            id[i] = e.size();
            r[e.size()] = i;
        } else {
            o.emplace_back(a[i]);
            id[i] = o.size() + n/2;
            r[o.size() + n/2] = i;
        }
    }
    if(e.size() != o.size()) {
        cout << "Impossible\n";
        return;
    }
    for(int i = 0; i < (int)e.size(); i++) {
        for(int j = 0; j < (int)o.size(); j++) {
            if(prime(e[i] + o[j])) {
                c[i + 1][j + n/2 + 1] = 1;
            }
        }
    }
    for(int i = 1; i <= n/2; i++) {
        c[0][i] = 2;
        c[i + n/2][n + 1] = 2;
    }
    int ans = 0;
    T++;
    while(dfs(0)) {
        T++;
        ans++;
    }
    if(ans != n) {
        cout << "Impossible\n";
        return;
    }
    int sz = 0;
    vector< vector<int> > A;
    for(int i = 1; i <= n; i++) {
        if(col[i] > 0) continue;
        ++sz;
        ord.clear();
        dfs2(i, sz);
        A.emplace_back(ord);
    }
    cout << sz << "\n";
    for(auto d: A) {
        cout << d.size();
        for(int v: d) {
            cout << " "<<v + 1;
        }
        cout << "\n";
    }
}

int main() {
    //ios_base::sync_with_stdio(0);
    //cin.tie(0);
    //srand(time(0));
    int t = 1;
    //scanf("%d", &t);
    //cin >> t;
    for(int i = 1; i <= t; i++) {
        //printf("Case %d: ", i);
        solve();
    }
    return 0;
}


///#include <stdio.h>
///#include <iostream>
///#include <cstring>
///#include <cmath>
///#include <algorithm>
///#include <string>
///#include <vector>
///#include <map>
///#include <set>
///#include <queue>
///#include <cstdlib>
///#include <limits>
///#include <iostream>
///#include <sstream>
///#include <unordered_set>
///#include <unordered_map>
///#include <random>
#include <bits/stdc++.h>
///#include <bits/stdtr1c++.h>
///#include <ext/pb_ds/assoc_container.hpp>
///#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
///using namespace __gnu_pbds;

#define              MAX             500005
#define              EPS             1e-9
#define              ull             unsigned long long
#define              ll              long long
#define              inf             INT_MAX
#define              pi              acos(-1.0)
#define              vi              vector<int>
#define              vl              vector<long long>
#define              pii             pair<int,int>
#define              pll             pair<long long,long long>
#define              mp              make_pair
#define              mem(a, v)       memset(a, v, sizeof (a))
#define              mod             1000000007
#define              all(a)          a.begin(),a.end()
#define              rall(a)         a.rbegin(),a.rend()
#define              ff              first
#define              ss              second
#define              arsort(ar,n)    sort(ar,ar+n);
#define              vsort(v)        sort(v.begin(),v.end())
#define              vrev(v)         reverse(v.begin(),v.end())
#define              arrev(ar,n)     reverse(ar,ar+n)
#define              pb              push_back
#define              popb            pop_back
#define              booster()       ios_base::sync_with_stdio(0); cin.tie(0);
#define              read(f)         freopen(f, "r", stdin)
#define              scani(x)        scanf("%d",&x)
#define              scanl(x)        scanf("%I64d",&x)
#define              scand(x)        scanf("%lf",&x)
#define              scans(x)        scanf("%s",x)
#define              OUT(x)          printf("%d\n",x)
#define              OUTS(x)         printf("%d ",x)
#define              min3(a,b,c)     min(a,min(b,c))
#define              max3(a,b,c)     max(a,max(b,c))
#define              min4(a,b,c,d)   min(min(a,b),min(c,d))
#define              max4(a,b,c,d)   max(max(a,b),max(c,d))
#define              max5(a,b,c,d,e) max(max3(a,b,c),max(d,e))
#define              min5(a,b,c,d,e) min(min3(a,b,c),min(d,e))

#define              bitCheck(a,k)     ((bool)(a&(1<<(k))))
#define              bitOff(a,k)       (a&(~(1<<(k))))
#define              bitOn(a,k)        (a|(1<<(k)))
#define              bitFlip(a,k)      (a^(1<<(k)))

#define              POPCOUNT           __builtin_popcount
#define              POPCOUNTLL         __builtin_popcountll
#define              RIGHTMOST          __builtin_ctzll
#define              LEFTMOST(x)        (63-__builtin_clzll((x)))

#define scani2(a,b) scani(a) , scani(b)
#define scani3(a,b,c) scani(a), scani(b), scani(c)
#define scani4(a,b,c,d) scani(a), scani(b), scani(c), scani(d)
#define scani5(a,b,c,d,e) scani(a), scani(b), scani(c), scani(d) , scani(e)
#define rnd mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

/*********************Ordered Multiset*************************/

/*** Needs C++11 or C++14 ***/
/// Treap supporting duplicating values in set
/// Maximum value of treap * ADD must fit in long long

/*

struct Treap{ /// hash = 96814
    int len;
    const int ADD = 1000010;
    const int MAXVAL = 1000000010;
    tr1::unordered_map <long long, int> mp; /// Change to int if only int in treap
    tree<long long, null_type, less<long long>, rb_tree_tag, tree_order_statistics_node_update> T;
    Treap(){
        len = 0;
        T.clear(), mp.clear();
    }
    inline void clear(){
        len = 0;
        T.clear(), mp.clear();
    }
    inline void insert(long long x){
        len++, x += MAXVAL;
        int c = mp[x]++;
        T.insert((x * ADD) + c);
    }
    inline void erase(long long x){
        x += MAXVAL;
        int c = mp[x];
        if (c){
            c--, mp[x]--, len--;
            T.erase((x * ADD) + c);
        }
    }
    /// 1-based index, returns the K'th element in the treap, -1 if none exists
    inline long long kth(int k){
        if (k < 1 || k > len) return -1;
        auto it = T.find_by_order(--k);
        return ((*it) / ADD) - MAXVAL;
    }
    /// Count of value < x in treap
    inline int count(long long x){
        x += MAXVAL;
        int c = mp[--x];
        return (T.order_of_key((x * ADD) + c));
    }
    /// Number of elements in treap
    inline int size(){
        return len;
    }
};

typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>ordered_set;///*X.find_by_order();X.order_of_key();
template <class T> inline bool isLeap(T y) {return (y % 400 == 0) || (y % 100 ? y % 4 == 0 : false); }*/
template< class T > inline T gcd(T a, T b) { return (b) == 0 ? (a) : gcd((b), ((a) % (b))); }
template< class T > inline T lcm(T a, T b) { return ((a) / gcd((a), (b)) * (b)); }
template <class T> inline T BigMod(T Base,T power,T M=mod){if(power==0)return 1;if(power&1)return ((Base%M)*(BigMod(Base,power-1,M)%M))%M;else{T y=BigMod(Base,power/2,M)%M;return (y*y)%M;}}
template <class T> inline T ModInv (T A,T M = mod){return BigMod(A,M-2,M);}

int fx[] = {-1,+0,+1,+0,+1,+1,-1,-1,+0};
int fy[] = {+0,-1,+0,+1,+1,-1,+1,-1,+0};
int day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/*********************** let the play begin() *********************************/

/// ********** FASTER one *******************///
namespace mf
{
    const int MAXN = 10004;
    struct edge {
        int a, b, cap, flow ;
        edge(int _a,int _b,int _c,int _d) {
            a=_a,b=_b,cap=_c,flow=_d;
        }
    } ;

    int INF=1500000001;

    int n, s, t, d [ MAXN*2 ] , ptr [ MAXN*2 ] , q [ MAXN*2*10 ] ;
    vector < edge > e ;
    vector < int > g [ MAXN * 2 ] ;

    void addEdge ( int a, int b, int cap ,int cap2=0) {
        edge e1 =edge( a, b, cap, 0 ) ; /// forward cap
        edge e2 =edge( b, a, cap2 , 0 ) ; /// backward cap change here if needed
        g [ a ] . push_back ( ( int ) e. size ( ) ) ;
        e. push_back ( e1 ) ;
        g [ b ] . push_back ( ( int ) e. size ( ) ) ;
        e. push_back ( e2 ) ;
    }

    bool bfs ( ) {
        int qh = 0 , qt = 0 ;
        q [ qt ++ ] = s ;
        memset ( d, -1 , sizeof d ) ;
        d [ s ] = 0 ;
        while ( qh < qt && d [ t ] == - 1 ) {
            int v = q [ qh ++ ] ;
            for ( size_t i = 0 ; i < g [ v ] . size ( ) ; ++ i ) {
                int id = g [ v ] [ i ] ,
                    to = e [ id ] . b ;
                if ( d [ to ] == - 1 && e [ id ] . flow < e [ id ] . cap ) {
                    q [ qt ++ ] = to ;
                    d [ to ] = d [ v ] + 1 ;
                }
            }
        }
        return d [ t ] != -1;
    }

    int dfs ( int v, int flow ) {
        if ( ! flow )  return 0 ;
        if ( v == t )  return flow ;
        for ( ; ptr [ v ] < ( int ) g [ v ] . size ( ) ; ++ ptr [ v ] ) {
            int id = g [ v ] [ ptr [ v ] ] ,
                to = e [ id ] . b ;
            if ( d [ to ] != d [ v ] + 1 )  continue ;
            int pushed = dfs ( to, min ( flow, e [ id ] . cap - e [ id ] . flow ) ) ;
            if ( pushed ) {
                e [ id ] . flow += pushed ;
                e [ id ^ 1 ] . flow -= pushed ;
                return pushed ;
            }
        }
        return 0 ;
    }

    ll dinic ( ) {
        ll flow = 0 ;
        for ( ;; ) {
            if ( !bfs () )  break ;
            memset ( ptr, 0 , sizeof ptr ) ;
            while ( int pushed = dfs ( s, INF ) ) {
                flow += (ll)pushed ;
                if(pushed == 0)break;
            }
        }
        return flow ;
    }

    void init(int src, int dest , int nodes){
        e.clear();
        for(int i = 0;i<=n+n;i++) g[i].clear();
        n = nodes; s = src; t = dest;
    }
};

int prime[MAX],p,flag[MAX];
void sieve(int n){
	double z = sqrt(n);
	for(int i = 3;i<=z;i+=2){
		if(!flag[i]){
			for(ll j = i*i;j<=n;j+=i+i)flag[j] = 1;
		}
	}
	prime[p++] = 2;
	for(int i = 3;i<=n;i+=2){
		if(!flag[i])prime[p++] = i;
	}
}

int nn,arr[MAX];vi v[MAX],ans[MAX];int vis[MAX],cnt;

void dfs(int s){
	vis[s] = 1;
	ans[cnt].pb(s);
	for(auto it : v[s]){
		if(!vis[it])dfs(it);
	}
}

int main()
{
    booster()
    ///read("input.txt");

    sieve(10000);

    cin>>nn;
    for(int i = 0;i<nn;i++){
		cin>>arr[i];
    }

    mf::init(0,nn+1,nn+3);

    for(int i = 0;i<nn;i++){
		for(int j = i+1;j<nn;j++){
			if(!flag[arr[i]+arr[j]]){
				if(arr[i]&1)mf::addEdge(i+1,j+1,1);
				else mf::addEdge(j+1,i+1,1);
			}
		}
    }
    for(int i = 0;i<nn;i++){
		if(arr[i]&1)mf::addEdge(0,i+1,2);
		else mf::addEdge(i+1,nn+1,2);
    }
    int x = mf::dinic();
	///cout<<x<<endl;
    if(x!=nn)cout<<"Impossible";
    else {
        for(int i = 0;i<nn;i++){
            int sz = mf::g[i+1].size();
            for(int j = 0;j<sz;j++){
				int indx = mf::g[i+1][j];
				if(mf::e[indx].flow==1){
                    int a = mf::e[indx].a;
                    int b = mf::e[indx].b;
                    v[a].pb(b);
                    v[b].pb(a);
				}
            }
        }

		for(int i = 1;i<=nn;i++){
			if(!vis[i]){
				cnt++;
				dfs(i);
			}
		}
		cout<<cnt<<endl;
		for(int i = 1;i<=cnt;i++){
			cout<<ans[i].size()<<" ";
			for(auto it : ans[i])cout<<it<<" ";
			cout<<endl;
		}
    }

    return 0;
}


///#include <stdio.h>
///#include <iostream>
///#include <cstring>
///#include <cmath>
///#include <algorithm>
///#include <string>
///#include <vector>
///#include <map>
///#include <set>
///#include <queue>
///#include <cstdlib>
///#include <limits>
///#include <iostream>
///#include <sstream>
///#include <unordered_set>
///#include <unordered_map>
///#include <random>
#include <bits/stdc++.h>
///#include <bits/stdtr1c++.h>
///#include <ext/pb_ds/assoc_container.hpp>
///#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
///using namespace __gnu_pbds;

#define              MAX             500005
#define              EPS             1e-9
#define              ull             unsigned long long
#define              ll              long long
#define              inf             INT_MAX
#define              pi              acos(-1.0)
#define              vi              vector<int>
#define              vl              vector<long long>
#define              pii             pair<int,int>
#define              pll             pair<long long,long long>
#define              mp              make_pair
#define              mem(a, v)       memset(a, v, sizeof (a))
#define              mod             1000000007
#define              all(a)          a.begin(),a.end()
#define              rall(a)         a.rbegin(),a.rend()
#define              ff              first
#define              ss              second
#define              arsort(ar,n)    sort(ar,ar+n);
#define              vsort(v)        sort(v.begin(),v.end())
#define              vrev(v)         reverse(v.begin(),v.end())
#define              arrev(ar,n)     reverse(ar,ar+n)
#define              pb              push_back
#define              popb            pop_back
#define              booster()       ios_base::sync_with_stdio(0); cin.tie(0);
#define              read(f)         freopen(f, "r", stdin)
#define              scani(x)        scanf("%d",&x)
#define              scanl(x)        scanf("%I64d",&x)
#define              scand(x)        scanf("%lf",&x)
#define              scans(x)        scanf("%s",x)
#define              OUT(x)          printf("%d\n",x)
#define              OUTS(x)         printf("%d ",x)
#define              min3(a,b,c)     min(a,min(b,c))
#define              max3(a,b,c)     max(a,max(b,c))
#define              min4(a,b,c,d)   min(min(a,b),min(c,d))
#define              max4(a,b,c,d)   max(max(a,b),max(c,d))
#define              max5(a,b,c,d,e) max(max3(a,b,c),max(d,e))
#define              min5(a,b,c,d,e) min(min3(a,b,c),min(d,e))

#define              bitCheck(a,k)     ((bool)(a&(1<<(k))))
#define              bitOff(a,k)       (a&(~(1<<(k))))
#define              bitOn(a,k)        (a|(1<<(k)))
#define              bitFlip(a,k)      (a^(1<<(k)))

#define              POPCOUNT           __builtin_popcount
#define              POPCOUNTLL         __builtin_popcountll
#define              RIGHTMOST          __builtin_ctzll
#define              LEFTMOST(x)        (63-__builtin_clzll((x)))

#define scani2(a,b) scani(a) , scani(b)
#define scani3(a,b,c) scani(a), scani(b), scani(c)
#define scani4(a,b,c,d) scani(a), scani(b), scani(c), scani(d)
#define scani5(a,b,c,d,e) scani(a), scani(b), scani(c), scani(d) , scani(e)
#define rnd mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

/*********************Ordered Multiset*************************/

/*** Needs C++11 or C++14 ***/
/// Treap supporting duplicating values in set
/// Maximum value of treap * ADD must fit in long long

/*

struct Treap{ /// hash = 96814
    int len;
    const int ADD = 1000010;
    const int MAXVAL = 1000000010;
    tr1::unordered_map <long long, int> mp; /// Change to int if only int in treap
    tree<long long, null_type, less<long long>, rb_tree_tag, tree_order_statistics_node_update> T;
    Treap(){
        len = 0;
        T.clear(), mp.clear();
    }
    inline void clear(){
        len = 0;
        T.clear(), mp.clear();
    }
    inline void insert(long long x){
        len++, x += MAXVAL;
        int c = mp[x]++;
        T.insert((x * ADD) + c);
    }
    inline void erase(long long x){
        x += MAXVAL;
        int c = mp[x];
        if (c){
            c--, mp[x]--, len--;
            T.erase((x * ADD) + c);
        }
    }
    /// 1-based index, returns the K'th element in the treap, -1 if none exists
    inline long long kth(int k){
        if (k < 1 || k > len) return -1;
        auto it = T.find_by_order(--k);
        return ((*it) / ADD) - MAXVAL;
    }
    /// Count of value < x in treap
    inline int count(long long x){
        x += MAXVAL;
        int c = mp[--x];
        return (T.order_of_key((x * ADD) + c));
    }
    /// Number of elements in treap
    inline int size(){
        return len;
    }
};

typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>ordered_set;///*X.find_by_order();X.order_of_key();
template <class T> inline bool isLeap(T y) {return (y % 400 == 0) || (y % 100 ? y % 4 == 0 : false); }*/
template< class T > inline T gcd(T a, T b) { return (b) == 0 ? (a) : gcd((b), ((a) % (b))); }
template< class T > inline T lcm(T a, T b) { return ((a) / gcd((a), (b)) * (b)); }
template <class T> inline T BigMod(T Base,T power,T M=mod){if(power==0)return 1;if(power&1)return ((Base%M)*(BigMod(Base,power-1,M)%M))%M;else{T y=BigMod(Base,power/2,M)%M;return (y*y)%M;}}
template <class T> inline T ModInv (T A,T M = mod){return BigMod(A,M-2,M);}

int fx[] = {-1,+0,+1,+0,+1,+1,-1,-1,+0};
int fy[] = {+0,-1,+0,+1,+1,-1,+1,-1,+0};
int day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/*********************** let the play begin() *********************************/

/// ********** FASTER one *******************///
namespace mf
{
    const int MAXN = 10004;
    struct edge {
        int a, b, cap, flow ;
        edge(int _a,int _b,int _c,int _d) {
            a=_a,b=_b,cap=_c,flow=_d;
        }
    } ;

    int INF=1500000001;

    int n, s, t, d [ MAXN*2 ] , ptr [ MAXN*2 ] , q [ MAXN*2*10 ] ;
    vector < edge > e ;
    vector < int > g [ MAXN * 2 ] ;

    void addEdge ( int a, int b, int cap ,int cap2=0) {
        edge e1 =edge( a, b, cap, 0 ) ; /// forward cap
        edge e2 =edge( b, a, cap2 , 0 ) ; /// backward cap change here if needed
        g [ a ] . push_back ( ( int ) e. size ( ) ) ;
        e. push_back ( e1 ) ;
        g [ b ] . push_back ( ( int ) e. size ( ) ) ;
        e. push_back ( e2 ) ;
    }

    bool bfs ( ) {
        int qh = 0 , qt = 0 ;
        q [ qt ++ ] = s ;
        memset ( d, -1 , sizeof d ) ;
        d [ s ] = 0 ;
        while ( qh < qt && d [ t ] == - 1 ) {
            int v = q [ qh ++ ] ;
            for ( size_t i = 0 ; i < g [ v ] . size ( ) ; ++ i ) {
                int id = g [ v ] [ i ] ,
                    to = e [ id ] . b ;
                if ( d [ to ] == - 1 && e [ id ] . flow < e [ id ] . cap ) {
                    q [ qt ++ ] = to ;
                    d [ to ] = d [ v ] + 1 ;
                }
            }
        }
        return d [ t ] != -1;
    }

    int dfs ( int v, int flow ) {
        if ( ! flow )  return 0 ;
        if ( v == t )  return flow ;
        for ( ; ptr [ v ] < ( int ) g [ v ] . size ( ) ; ++ ptr [ v ] ) {
            int id = g [ v ] [ ptr [ v ] ] ,
                to = e [ id ] . b ;
            if ( d [ to ] != d [ v ] + 1 )  continue ;
            int pushed = dfs ( to, min ( flow, e [ id ] . cap - e [ id ] . flow ) ) ;
            if ( pushed ) {
                e [ id ] . flow += pushed ;
                e [ id ^ 1 ] . flow -= pushed ;
                return pushed ;
            }
        }
        return 0 ;
    }

    ll dinic ( ) {
        ll flow = 0 ;
        for ( ;; ) {
            if ( !bfs () )  break ;
            memset ( ptr, 0 , sizeof ptr ) ;
            while ( int pushed = dfs ( s, INF ) ) {
                flow += (ll)pushed ;
                if(pushed == 0)break;
            }
        }
        return flow ;
    }

    void init(int src, int dest , int nodes){
        e.clear();
        for(int i = 0;i<=n+n;i++) g[i].clear();
        n = nodes; s = src; t = dest;
    }
};

int prime[MAX],p,flag[MAX];
void sieve(int n){
	double z = sqrt(n);
	for(int i = 4;i<=n;i+=2)flag[i] = 1;
	for(int i = 3;i<=z;i+=2){
		if(!flag[i]){
			for(ll j = i*i;j<=n;j+=i+i)flag[j] = 1;
		}
	}
	prime[p++] = 2;
	for(int i = 3;i<=n;i+=2){
		if(!flag[i])prime[p++] = i;
	}
}

int nn,arr[MAX];vi v[MAX],ans[MAX];int vis[MAX],cnt;

void dfs(int s){
	if(vis[s])return ;
	vis[s] = 1;
	ans[cnt].pb(s);
	for(auto it : v[s]){
		if(!vis[it])dfs(it);
	}
}

int main()
{
    booster()
    ///read("input.txt");

    sieve(100000);

    cin>>nn;
    for(int i = 0;i<nn;i++){
		cin>>arr[i];
    }

    mf::init(0,nn+1,nn+3);

    for(int i = 0;i<nn;i++){
		for(int j = i+1;j<nn;j++){
			if(!flag[arr[i]+arr[j]]){
				if(arr[i]&1)mf::addEdge(i+1,j+1,1);
				else mf::addEdge(j+1,i+1,1);
			}
		}
    }
    int pnt = 0;
    for(int i = 0;i<nn;i++){
		if(arr[i]&1)mf::addEdge(0,i+1,2),pnt++;
		else mf::addEdge(i+1,nn+1,2);
    }
    int x = mf::dinic();
	///cout<<x<<endl;
    if(x!=nn||pnt!=nn-pnt)cout<<"Impossible";
    else {
        for(int i = 0;i<nn;i++){
            int sz = mf::g[i+1].size();
            for(int j = 0;j<sz;j++){
				int indx = mf::g[i+1][j];
				if(mf::e[indx].flow==1){
                    int a = mf::e[indx].a;
                    int b = mf::e[indx].b;
                    v[a].pb(b);
                    v[b].pb(a);
				}
            }
        }

		for(int i = 1;i<=nn;i++){
			if(!vis[i]){
				cnt++;
				dfs(i);
			}
		}
		cout<<cnt<<endl;
		for(int i = 1;i<=cnt;i++){
			cout<<ans[i].size()<<" ";
			for(auto it : ans[i])cout<<it<<" ";
			cout<<endl;
		}
    }

    return 0;
}