AtCoder-ARC080D Prime Flip——Differential + Goldbach Conjecture

topic

AtCoder - arc080_d 

answer

A very clever question.

Direct operation is obviously not easy to do. The array difference is changed to only the first one and the last one at the end of each continuous upwards are 1, and the remaining positions are 0. Each operation is in the interval [l,r] (requires rl to be odd Prime number) flip the 0/1 at l and r, and require that all become zero at the end.

It is easy to find that the number of 1 after the difference must be an even number, so it must be eliminated by pairwise flipping.

Let's briefly discuss the classification of rl, there are three situations:

  1. rl is an odd prime number, and the operation is once;
  2. rl is an even number, what should I do at this time? When we see odd prime numbers, we think of Goldbach’s conjecture learned in the third grade of elementary school: any even number greater than 4 can be expressed as the addition of two odd prime numbers, such as 6=3+3, 8=3=5. Although it is a conjecture, it is correct at least within 1e7. In addition, for even numbers less than or equal to 4, 2, 4, 2=5-3, 4=7-3, so the operation only needs 2 times at this time.
  3. rl is an odd non-prime number, because 1=7-3-3, and all odd non-prime numbers except 1 -3 are even numbers greater than 4, so it needs to be operated 3 times.

Then we need to match 1 in pairs. We can first separate the position of 1 according to the parity to form a bipartite graph. The difference is odd prime number connected edges, and run a bipartite graph matching (each edge contributes 1), and the rest Click the odd-odd, even-even pairwise match to delete, and contribute 2. If there is any remaining, it must be an odd one even and the difference is an odd non-prime number, and then a contribution 3.

Use Hungary + simplicity to judge prime numbers O(n^3+n^2\sqrt X), use Euler to sieve yes O(n^3+X),

If you use DINIC to run the matching can be faster, the total complexity is about O(n^2\sqrt X)or O(X),

You can also \sqrt Xsift out the prime numbers inside and judge with simplicity, complexityO(\frac{n^2\sqrt X}{\ln \sqrt X})

If you want to be faster, you can use the Miller-Rabin algorithm, but it's not necessary, just after that

Code

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

 

Guess you like

Origin blog.csdn.net/weixin_43960287/article/details/113838253