tema
respuesta
Una pregunta muy inteligente.
La operación directa obviamente no es fácil de hacer. La diferencia de la matriz se cambia a solo la primera y la última al final de cada continuo ascendente es 1, y las posiciones restantes son 0. Cada operación está en el intervalo [l, r ] (requiere que rl sea un número primo impar) voltea el 0/1 en lyr, y requiere que todos se conviertan en cero al final.
Es fácil encontrar que el número 1 después de la diferencia debe ser un número par, por lo que debe eliminarse volteando por pares.
Analicemos brevemente la clasificación de rl, hay tres situaciones:
- rl es un número primo impar y la operación es una vez;
- rl es un número par, ¿qué debo hacer en este momento? Cuando vemos números primos impares, pensamos en la conjetura de Goldbach aprendida en el tercer grado de la escuela primaria: cualquier número par mayor que 4 se puede expresar como la suma de dos números primos impares, como 6 = 3 + 3, 8 = 3 = 5. Aunque es una conjetura, es correcta al menos dentro de 1e7. Además, para números pares menores o iguales a 4, 2, 4, 2 = 5-3, 4 = 7-3, la operación solo necesita 2 veces en este momento.
- rl es un número no primo impar, porque 1 = 7-3-3, y todos los números no primos impares excepto 1-3 son números pares mayores que 4, por lo que debe operarse 3 veces.
Luego, necesitamos hacer coincidir 1 en pares. Primero, podemos separar la posición de 1 de acuerdo con la paridad para formar un gráfico bipartito. La diferencia es un número primo impar con bordes conectados y ejecutar un gráfico bipartito que coincida (cada borde contribuye con 1), y el resto Haga clic en la coincidencia de pares impar-impar, par-par para eliminar y contribuir 2. Si queda algo, debe ser un número par impar y la diferencia es un número impar no primo, y luego una contribución 3.
Use Hungría + simplicidad para juzgar números primos , use Euler para tamizar sí ,
Si usa DINIC para ejecutar el emparejamiento puede ser más rápido, la complejidad total es de aproximadamente o ,
También puede filtrar los números primos en el interior y juzgar con simplicidad y complejidad.
Si quieres ser más rápido, puedes usar el algoritmo Miller-Rabin , pero no es necesario, justo después de eso.
Código
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
#define MAXN 100005
#define MAXX 10000000
#define INF 0x3f3f3f3f
using namespace std;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
return f?x:-x;
}
int n,m,a[205],ans;
bool nop[MAXN];
vector<int>pr;
inline int ads(int x){return x>0?x:-x;}
inline void getprime(int n){
nop[0]=nop[1]=1;
for(int a=2;a<=n;a++){
if(!nop[a])pr.push_back(a);
for(int i=0;i<pr.size()&&pr[i]*a<=n;i++){
nop[pr[i]*a]=1;
if(a%pr[i]==0)break;
}
}
}
inline bool isprime(int x){
if(x<MAXN-4)return !nop[x];
for(int i=0;i<pr.size()&&pr[i]*pr[i]<=x;i++)
if(x%pr[i]==0)return 0;
return 1;
}
int f[100005],cur[505],c,d,s1[205],s2[205],IN;
int dt[505];
struct edge{
int v,id;edge(){}
edge(int V,int I){v=V,id=I;}
};
vector<edge>G[505];
queue<int>q;
inline void addedge(int u,int v,int w){
f[IN]=w,f[IN^1]=0;
G[u].push_back(edge(v,IN)),G[v].push_back(edge(u,IN^1));
IN+=2;
}
inline bool bfs(int S,int T){
while(!q.empty())q.pop();
memset(dt,-1,sizeof(dt));
dt[S]=0,q.push(S);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++)
if(f[G[u][i].id]>0&&dt[G[u][i].v]<0)
dt[G[u][i].v]=dt[u]+1,q.push(G[u][i].v);
}
return dt[T]>=0;
}
inline int dfs(int x,int lim,int T){
if(x==T)return lim;
int res=lim;
for(int i=cur[x];i<G[x].size()&&res>0;i++){
cur[x]=i;
int v=G[x][i].v,a=G[x][i].id;
if(f[a]>0&&dt[v]==dt[x]+1){
int ad=dfs(v,min(res,f[a]),T);
f[a]-=ad,f[a^1]+=ad,res-=ad;
}
}
return lim-res;
}
inline int dinic(int S,int T){
int res=0;
while(bfs(S,T)){
memset(cur,0,sizeof(cur));
while(int ad=dfs(S,INF,T))res+=ad;
}
return res;
}
signed main()
{
n=read();
getprime(MAXN-5);
for(int i=1,ls=-1;i<=n;i++){
int x=read();
if(x>ls+1)a[++m]=x,a[++m]=x+1;
else a[m]++;
ls=x;
}
for(int i=1;i<=m;i++){
if(a[i]&1)s1[++c]=a[i];
else s2[++d]=a[i];
}
for(int i=1;i<=c;i++)addedge(0,i,1);
for(int i=1;i<=d;i++)addedge(c+i,c+d+1,1);
for(int i=1;i<=c;i++)
for(int j=1,s;j<=d;j++){
s=ads(s1[i]-s2[j]);
if((s&1)&&isprime(s))addedge(i,c+j,1);
}
int p=ans=dinic(0,c+d+1);
ans+=c+d-p-p;
if((c-p&1)&&(d-p&1))ans++;
printf("%d\n",ans);
return 0;
}