如果a+b是素数,那它是奇数=奇数+偶数
原题的环就变成 ji,ou,ji,ou。。。这样的 ,所以年龄中,奇数个数=偶数个数
把奇数,偶数换在2边,做2分图,a+b是素数就连边。
原题转变成一个2分图匹配,每个点要匹配2条边
故:建s,t,s向每个偶数连容量为2的边,同理,奇数向t连
建图,网络流
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (400+10)
#define MAXM ((200+100*100)*2+100000)
#define MAXAi (10000+10)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
int n,a[MAXN],a1[MAXN],a2[MAXN],num1[MAXN],num2[MAXN];
class Max_flow //dinic+当前弧优化
{
public:
int n,s,t;
int q[MAXN];
int edge[MAXM],next[MAXM],pre[MAXN],weight[MAXM],size;
void addedge(int u,int v,int w)
{
edge[++size]=v;
weight[size]=w;
next[size]=pre[u];
pre[u]=size;
}
void addedge2(int u,int v,int w){addedge(u,v,w),addedge(v,u,0);}
bool b[MAXN];
int d[MAXN];
bool SPFA(int s,int t)
{
For(i,n) d[i]=INF;
MEM(b)
d[q[1]=s]=0;b[s]=1;
int head=1,tail=1;
while (head<=tail)
{
int now=q[head++];
Forp(now)
{
int &v=edge[p];
if (weight[p]&&!b[v])
{
d[v]=d[now]+1;
b[v]=1,q[++tail]=v;
}
}
}
return b[t];
}
int iter[MAXN];
int dfs(int x,int f)
{
if (x==t) return f;
Forpiter(x)
{
int v=edge[p];
if (weight[p]&&d[x]<d[v])
{
int nowflow=dfs(v,min(weight[p],f));
if (nowflow)
{
weight[p]-=nowflow;
weight[p^1]+=nowflow;
return nowflow;
}
}
}
return 0;
}
int max_flow(int s,int t)
{
int flow=0;
while(SPFA(s,t))
{
For(i,n) iter[i]=pre[i];
int f;
while (f=dfs(s,INF))
flow+=f;
}
return flow;
}
void mem(int n,int s,int t)
{
(*this).n=n;
(*this).t=t;
(*this).s=s;
size=1;
MEM(pre)
}
}S;
int p[MAXAi*2]={0},size=0;
bool b[MAXAi*2]={0};
const int N=20000;
void make_prime()
{
MEM(b)
Fork(i,2,N)
{
if (!b[i]) p[++size]=i;
For(j,size)
{
if (p[j]*i>N) break;
b[p[j]*i]=1;
if (i%p[j]==0) break;
}
}
}
int ans[MAXN][3],st[MAXN][MAXN]={0};
int main()
{
// freopen("CF510E.in","r",stdin);
// freopen(".out","w",stdout);
make_prime();
cin>>n;
int n1=0,n2=0;
For(i,n)
{
scanf("%d",&a[i]);
if (a[i]&1) a1[++n1]=a[i],num1[n1]=i;
else a2[++n2]=a[i],num2[n2]=i;
}
if (n1^n2)
{
cout<<"Impossible"<<endl;
return 0;
}
else
{
const int s=1,t=n+2;
S.mem(t,s,t);
For(i,n1) S.addedge2(s,i+1,2);
For(i,n2) S.addedge2(1+n1+i,t,2);
For(i,n1)
For(j,n2)
if (!b[a1[i]+a2[j]])
S.addedge2(i+1,1+n1+j,1);
if (S.max_flow(s,t)^n)
{
cout<<"Impossible"<<endl;
return 0;
}
else
{
int tot=0;
For(i,n1)
{
for(int p=S.pre[i+1];p;p=S.next[p])
{
if (S.weight[p]==0) ans[++tot][1]=num1[i],ans[tot][2]=num2[S.edge[p]-1-n1];
}
}
MEM(b)
// For(i,tot) cout<<ans[i][1]<<' '<<ans[i][2]<<endl;
int m=0;
For(i,tot)
if (!b[i])
{
b[i]=1;
st[++m][1]=ans[i][1],st[m][2]=ans[i][2];
int st_size=2;
while (st[m][1]^st[m][st_size])
{
For(i,tot)
if (!b[i])
{
if (ans[i][1]==st[m][st_size]) {st[m][++st_size]=ans[i][2];b[i]=1; break;}
if (ans[i][2]==st[m][st_size]) {st[m][++st_size]=ans[i][1];b[i]=1; break;}
}
}
st[m][0]=st_size-1;
}
cout<<m<<endl;
For(i,m)
{
cout<<st[i][0];
For(j,st[i][0]) printf(" %d",st[i][j]);
putchar('\n');
}
}
}
return 0;
}