F.小红的数组分组

文章描述了一种优化算法,用于解决关于集合中元素具有相同质因子的问题,通过预处理质数和最小质因子,避免重复访问和超时,以高效地找出满足条件的元素组合。
摘要由CSDN通过智能技术生成

 解题思路

  • 维护集合,满足集合内一个元素一定存在另一个元素与其有某一个相同的质因子(size>1)
  • 若集合只有一个,则无解
  • 特判存在1,则1单独放一个,其余放一起
  • 预处理出1e6内所有质数的同时,可以处理出每个数的最小质因子
  • 对于任意一个数,while(x/=mifac[x])可以得到该数所有质因子
  • 避免了对于1e6内某一数进行质因数分解时
  • while2开始++查找 或 利用已经求出的质数for从小到大进行尝试
  • 注意维护集合时,不要通过质因子将其能整除的一块处理,因为会有已经被处理过的,虽然不计,但会访问,重复访问会超时
  • 而自己处理自己的,相互之间通过质因子进行联系,这样每个至多访问一次
  • 注意java不要在循环中建数组,会超时。直接建全局,结束时进行删除即可。

最优解 


import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;







public class Main{
	static long md=(long)998244353;
	static long Linf=Long.MAX_VALUE/2;
	static int inf=Integer.MAX_VALUE/2;
	
	
	static int find(int x,int[] fa) {
		if(x==fa[x])return x;
		else return fa[x]=find(fa[x], fa);
	}
	 
	
	public static void main(String[] args) throws IOException{
		AReader input=new AReader();
	    PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	    int N=1000000;
	    int[] prim=new int[1000001];
	    int cnt=0;
	    boolean[] isnotprim=new boolean[1000001];
	    int[] facmi=new int[1000001];
	    for(int i=2;i<=N;++i) {
	    	if(!isnotprim[i]) {
	    		cnt++;
	    		prim[cnt]=i;
	    		facmi[i]=i;
	    	}
	    	for(int j=1;j<=cnt;++j) {
	    		int now=prim[j]*i;
	    		if(now>N)break;
	    		isnotprim[now]=true;
	    		facmi[now]=prim[j];
	    		if(i%prim[j]==0)break;
	    	}
	    }
	    int[] a=new int[200001];
	    int[] b=new int[200001];
	    int[] c=new int[200001];
	    int[] fa=new int[1000001];
	    HashSet<Integer> ol=new HashSet<Integer>();
	    int q=input.nextInt();
	    while(q>0) {
	    	
	    	int n=input.nextInt();
	    	
	    	int one=0;
	    	int mx=0;
	    	for(int i=1;i<=n;++i) {
	    		a[i]=input.nextInt();
	    		fa[a[i]]=a[i];
	    		ol.add(a[i]);
	    		mx=Math.max(mx, a[i]);
	    	}
	    	if(one!=0) {
	    		out.println(one+" "+(n-one));
	    		for(int i=1;i<=one;++i) {
	    			out.print(1+" ");
	    		}
	    		out.println();
	    		for(int i=1;i<=n;++i) {
	    			if(a[i]!=1)out.print(a[i]+" ");
	    		}
	    		out.println();
	    		q--;
	    		for(int x:ol) {
	    			fa[x]=0;
	    		}
	    		ol.clear();
	    		continue;
	    	}
	    	for(int i=1;i<=cnt;++i) {
	    		if(prim[i]>mx)break;
	    		fa[prim[i]]=prim[i];
	    		ol.add(prim[i]);
	    	}
//	    	boolean[] vis=new boolean[mx+1];//其实还可以去个重
	    	for(int i=1;i<=n;++i) {
//	    		if(vis[a[i]])continue;
//	    		vis[a[i]]=true;
	    		int x=a[i];
	    		int fx=find(x, fa);
	    		while(x!=1) {
	    			int y=facmi[x];
	    			int fy=find(y, fa);
	    			if(fy!=fx)fa[fy]=fx;
	    			x/=y;
	    		}
	    	}
	    	
	    	
	    	int bb=0;
	    	int cc=0;
	    	int bf=find(a[1], fa);
	    	for(int i=1;i<=n;++i) {
	    		int fx=find(a[i], fa);
	    		if(fx==bf) {
	    			bb++;
	    			b[bb]=a[i];
	    		}else {
	    			cc++;
	    			c[cc]=a[i];
	    		}
	    	}
	    	if(bb==n) {
	    		out.println("-1 -1");
	    		q--;
	    		for(int x:ol) {
	    			fa[x]=0;
	    		}
	    		ol.clear();
	    		continue;
	    	}
	    	out.println(bb+" "+cc);
	    	for(int i=1;i<=bb;++i) {
	    		out.print(b[i]+" ");
	    	}
	    	out.println();
	    	for(int i=1;i<=cc;++i) {
	    		out.print(c[i]+" ");
	    	}
	    	out.println();
	    	q--;
	    	for(int x:ol) {
    			fa[x]=0;
    		}
    		ol.clear();
	    }
	    
 	    out.flush();
	    out.close();
	}
	//System.out.println();
	//out.println();
	static
	class AReader{ 
	    BufferedReader bf;
	    StringTokenizer st;
	    BufferedWriter bw;

	    public AReader(){
	        bf=new BufferedReader(new InputStreamReader(System.in));
	        st=new StringTokenizer("");
	        bw=new BufferedWriter(new OutputStreamWriter(System.out));
	    }
	    public String nextLine() throws IOException{
	        return bf.readLine();
	    }
	    public String next() throws IOException{
	        while(!st.hasMoreTokens()){
	            st=new StringTokenizer(bf.readLine());
	        }
	        return st.nextToken();
	    }
	    public char nextChar() throws IOException{
	        //确定下一个token只有一个字符的时候再用
	        return next().charAt(0);
	    }
	    public int nextInt() throws IOException{
	        return Integer.parseInt(next());
	    }
	    public long nextLong() throws IOException{
	        return Long.parseLong(next());
	    }
	    public double nextDouble() throws IOException{
	        return Double.parseDouble(next());
	    }
	    public float nextFloat() throws IOException{
	        return Float.parseFloat(next());
	    }
	    public byte nextByte() throws IOException{
	        return Byte.parseByte(next());
	    }
	    public short nextShort() throws IOException{
	        return Short.parseShort(next());
	    }
	    public BigInteger nextBigInteger() throws IOException{
	        return new BigInteger(next());
	    }
	    public void println() throws IOException {
	        bw.newLine();
	    }
	    public void println(int[] arr) throws IOException{
	        for (int value : arr) {
	            bw.write(value + " ");
	        }
	        println();
	    }
	    public void println(int l, int r, int[] arr) throws IOException{
	        for (int i = l; i <= r; i ++) {
	            bw.write(arr[i] + " ");
	        }
	        println();
	    }
	    public void println(int a) throws IOException{
	        bw.write(String.valueOf(a));
	        bw.newLine();
	    }
	    public void print(int a) throws IOException{
	        bw.write(String.valueOf(a));
	    }
	    public void println(String a) throws IOException{
	        bw.write(a);
	        bw.newLine();
	    }
	    public void print(String a) throws IOException{
	        bw.write(a);
	    }
	    public void println(long a) throws IOException{
	        bw.write(String.valueOf(a));
	        bw.newLine();
	    }
	    public void print(long a) throws IOException{
	        bw.write(String.valueOf(a));
	    }
	    public void println(double a) throws IOException{
	        bw.write(String.valueOf(a));
	        bw.newLine();
	    }
	    public void print(double a) throws IOException{
	        bw.write(String.valueOf(a));
	    }
	    public void print(char a) throws IOException{
	        bw.write(String.valueOf(a));
	    }
	    public void println(char a) throws IOException{
	        bw.write(String.valueOf(a));
	        bw.newLine();
	    }
	}
}


 超时解

  • 会超最后一个点,也是赛时代码
import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;







public class Main{
	static long md=(long)998244353;
	static long Linf=Long.MAX_VALUE/2;
	static int inf=Integer.MAX_VALUE/2;
	
	
	static int find(int x,int[] fa) {
		if(x==fa[x])return x;
		else return fa[x]=find(fa[x], fa);
	}
	 
	
	public static void main(String[] args) throws IOException{
		AReader input=new AReader();
	    PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	  
	    HashMap<Integer, HashSet<Integer>> NumhsPrim=new HashMap<Integer, HashSet<Integer>>();//每个数的质因子
	   
	    HashSet<Integer> now=new HashSet<Integer>();
	    
	    
	    int q=input.nextInt();
	    while(q>0) {
	    	int n=input.nextInt();
	    	int[] a=new int[n+3];
	    	for(int i=1;i<=n;++i)a[i]=input.nextInt();
	    	Arrays.sort(a,1,n+1);
	    	HashMap<Integer, Integer> d=new HashMap<Integer, Integer>();//统计相同个数
	    	int o=0;
	    	for(int i=1;i<=n+1;++i) {
	    		if(a[i]==a[i-1]) {
	    			o++;
	    		}else {
	    			d.put(a[i-1], o);
	    			o=1;
	    		}
	    	}
	    	int[] e=new int[n+1];o=0;//去重
	    	for(int i=1;i<=n;++i) {
	    		if(a[i]==a[i-1])continue;
	    		o++;
	    		e[o]=a[i];
	    	}
	    	
	    	int[] b=new int[n+1];
	    	int bc=0;
	    	int[] c=new int[n+1];
	        int cc=0;
	    	if(e[1]==1) {//1自己为一组,其它放一组
                bc=d.get(1);
                
	    		
	    		for(int i=2;i<=o;++i) {
	    			int p=d.get(e[i]);
	    			for(int j=1;j<=p;++j) {
	    				cc++;
	    				c[cc]=e[i];
	    			}
	    		}
	    		out.println(bc+" "+cc);
	    		for(int i=1;i<=bc;++i) {
	    			out.print(1+" ");
	    		}
	    		out.println();
	    		for(int i=1;i<=cc;++i) {
	    			out.print(c[i]+" ");
	    		}
	    		out.println();
	    	}else {
	    		
	    		for(int i=1;i<=o;++i) {
	    			if(NumhsPrim.get(e[i])==null) {
	    				now=new HashSet<Integer>();
	    				int x=e[i];
	    				int t=2;
	    				while(t<=x) {
	    					if(t==x) {
	    						now.add(t);
	    						break;
	    					}else if(x%t==0) {
	    						now.add(t);
	    						while(x%t==0) {
	    							x/=t;
	    						}
	    					}else t++;
	    				}
	    				NumhsPrim.put(e[i], now);
	    			}
	    		}
	    		
	    		Queue<Integer> qu=new LinkedList<Integer>();
	    		HashSet<Integer> checkover=new HashSet<Integer>();//被处理过的质数不在重复处理
	    		
	    		//该质数是哪些数的因子
	    		HashMap<Integer, Vector<Integer>> PrimhsNum=new HashMap<Integer, Vector<Integer>>();
	    		Vector<Integer> may=new Vector<Integer>();
	    		HashSet<Integer> op=new HashSet<Integer>();
	    		for(int i=1;i<=o;++i) {
	    			op=NumhsPrim.get(e[i]);
	    			for(int x:op) {//该数的所有质因子
	    				if(PrimhsNum.get(x)==null) {
	    					may=new Vector<Integer>();
	    					may.add(i);
	    					PrimhsNum.put(x, may);
	    				}else {
	    					may=PrimhsNum.get(x);
	    					may.add(i);
	    					PrimhsNum.put(x, may);
	    				}
	    			}
	    		}
	    		int[] fa=new int[n+1];
	    		for(int i=1;i<=o;++i)fa[i]=i;
	    		//集合内某一元素一定存在另一个元素与其有相同因子
	    		for(int i=1;i<=o;++i) {
	    			if(fa[i]!=i)continue;
	    			qu=new LinkedList<Integer>();
	    			checkover=new HashSet<Integer>();
	    			op=NumhsPrim.get(e[i]);
	    			for(int x:op) {
	    				qu.add(x);
	    			}
	    			int fx=i;
	    			while(!qu.isEmpty()) {
	    				int x=qu.peek();
	    				qu.poll();
	    				if(checkover.contains(x))continue;
	    				checkover.add(x);
	    				may=PrimhsNum.get(x);
	    				for(int y:may) {//会有重复访问,超时!!!!!
	    					int fy=find(y, fa);
	    					if(fy==fx)continue;//已经处理过了
	    					fa[fy]=fx;
	    					op=NumhsPrim.get(e[y]);
	    					for(int z:op) {//将新的质因子加入
	    						if(!checkover.contains(z)) {
	    							qu.add(z);
	    						}
	    					}
	    				}
	    			}
	    		}
	    		int m=0;
	    		for(int i=1;i<=o;++i) {//有多少个连通块
	    			if(fa[i]==i)m++;
	    		}
	    		if(m==1) {//只有一个连通块,分不开
	    			out.println("-1 -1");
	    		}else {
	    			op=new HashSet<Integer>();
	    			now=new HashSet<Integer>();
	    			int p=0;
	    			for(int i=1;i<=o;++i) {
	    				if(fa[i]==i) {//块头决定放在b/c
	    					if(p==0) {
	    						op.add(i);
	    						int l=d.get(e[i]);
	    						for(int j=1;j<=l;++j) {
	    							bc++;
	    							b[bc]=e[i];
	    						}
                                p=1;
	    					}else {
	    						now.add(i);
	    						int l=d.get(e[i]);
	    						for(int j=1;j<=l;++j) {
	    							cc++;
	    							c[cc]=e[i];
	    						}
                                p=0;
	    					}
	    				}else {
	    					if(op.contains(fa[i])) {//跟着放进去
	    						int l=d.get(e[i]);
	    						for(int j=1;j<=l;++j) {
	    							bc++;
	    							b[bc]=e[i];
	    						}
	    					}else {
	    						int l=d.get(e[i]);
	    						for(int j=1;j<=l;++j) {
	    							cc++;
	    							c[cc]=e[i];
	    						}
	    					}
	    				}
	    			}
	    			out.println(bc+" "+cc);
	    			for(int i=1;i<=bc;++i) {//输出
	    				out.print(b[i]+" ");
	    			}
	    			out.println();
	    			for(int i=1;i<=cc;++i) {
	    				out.print(c[i]+" ");
	    			}
	    			out.println();
	    		}
	    	}
	    	
	    	
	    	
	    	q--;
	    }
 	    out.flush();
	    out.close();
	}
	//System.out.println();
	//out.println();
	static
	class AReader{ 
	    BufferedReader bf;
	    StringTokenizer st;
	    BufferedWriter bw;

	    public AReader(){
	        bf=new BufferedReader(new InputStreamReader(System.in));
	        st=new StringTokenizer("");
	        bw=new BufferedWriter(new OutputStreamWriter(System.out));
	    }
	    public String nextLine() throws IOException{
	        return bf.readLine();
	    }
	    public String next() throws IOException{
	        while(!st.hasMoreTokens()){
	            st=new StringTokenizer(bf.readLine());
	        }
	        return st.nextToken();
	    }
	    public char nextChar() throws IOException{
	        //确定下一个token只有一个字符的时候再用
	        return next().charAt(0);
	    }
	    public int nextInt() throws IOException{
	        return Integer.parseInt(next());
	    }
	    public long nextLong() throws IOException{
	        return Long.parseLong(next());
	    }
	    public double nextDouble() throws IOException{
	        return Double.parseDouble(next());
	    }
	    public float nextFloat() throws IOException{
	        return Float.parseFloat(next());
	    }
	    public byte nextByte() throws IOException{
	        return Byte.parseByte(next());
	    }
	    public short nextShort() throws IOException{
	        return Short.parseShort(next());
	    }
	    public BigInteger nextBigInteger() throws IOException{
	        return new BigInteger(next());
	    }
	    public void println() throws IOException {
	        bw.newLine();
	    }
	    public void println(int[] arr) throws IOException{
	        for (int value : arr) {
	            bw.write(value + " ");
	        }
	        println();
	    }
	    public void println(int l, int r, int[] arr) throws IOException{
	        for (int i = l; i <= r; i ++) {
	            bw.write(arr[i] + " ");
	        }
	        println();
	    }
	    public void println(int a) throws IOException{
	        bw.write(String.valueOf(a));
	        bw.newLine();
	    }
	    public void print(int a) throws IOException{
	        bw.write(String.valueOf(a));
	    }
	    public void println(String a) throws IOException{
	        bw.write(a);
	        bw.newLine();
	    }
	    public void print(String a) throws IOException{
	        bw.write(a);
	    }
	    public void println(long a) throws IOException{
	        bw.write(String.valueOf(a));
	        bw.newLine();
	    }
	    public void print(long a) throws IOException{
	        bw.write(String.valueOf(a));
	    }
	    public void println(double a) throws IOException{
	        bw.write(String.valueOf(a));
	        bw.newLine();
	    }
	    public void print(double a) throws IOException{
	        bw.write(String.valueOf(a));
	    }
	    public void print(char a) throws IOException{
	        bw.write(String.valueOf(a));
	    }
	    public void println(char a) throws IOException{
	        bw.write(String.valueOf(a));
	        bw.newLine();
	    }
	}
}
//想要处理出1e6内所有数分解后的质因数
//对于每次询问的a,进行质因数分解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值