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