AtCoder-ARC080D Prime Flip —— Conjetura del diferencial + Goldbach

tema

AtCoder - arc080_d 

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:

  1. rl es un número primo impar y la operación es una vez;
  2. 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.
  3. 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 O (n ^ 3 + n ^ 2 \ sqrt X), use Euler para tamizar sí O (n ^ 3 + X),

Si usa DINIC para ejecutar el emparejamiento puede ser más rápido, la complejidad total es de aproximadamente O (n ^ 2 \ sqrt X)o BUEY),

También puede \ sqrt Xfiltrar los números primos en el interior y juzgar con simplicidad y complejidad.O (\ frac {n ^ 2 \ sqrt X} {\ ln \ sqrt X})

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;
}

 

Supongo que te gusta

Origin blog.csdn.net/weixin_43960287/article/details/113838253
Recomendado
Clasificación