CF1325E
题目描述
题解
大好题啊,转换为图论做,太妙了
首先对每个数进行质因数分解,可以线性筛完成,我们将其中偶数个的素数因子都丢掉,由于题目限制,每个数的因数个数不超过
7
7
7个,所以最后每个数剩下的质因数只有
1
1
1或
2
2
2个。然后最关键也是最妙的一步就是:
1.如果剩下的质因数个数为
2
2
2,我们就将这
2
2
2个质因数连接起来
2,如果剩下的质因数个数为
1
1
1,我们就将
1
1
1和这个质因数连接起来
那么这条边表示什么意思呢,表示如果我们走了这条边,那么我们就选择了这个数,于是每条边都代表一个数,因此问题转换了求无向图的最小环,
W
h
y
?
Why?
Why?,我们考虑一个环,环中的每个点的度数都为
2
2
2,因此每个质因数都成了偶数个,那么最后一定满足乘积为完全平方,又因为求最少选出多少个,所以是求最小环.
那么求最小环又成了一个难题,如果枚举每个点来作为起点,然后
B
F
S
BFS
BFS,那么肯定
T
T
T飞,我们考虑优化,由于
1
≤
a
i
≤
1
e
6
1\le a_i\le 1e6
1≤ai≤1e6,于是每个数的边不可能连接两个大于
1000
1000
1000的质数,因此边的一个端点一定是
[
1
,
1000
]
[1,1000]
[1,1000],于是环中的点肯定包含
[
1
,
1000
]
[1,1000]
[1,1000]中的数,我们枚举
[
1
,
1000
]
[1,1000]
[1,1000]中的质数为起点即可
代码
#include<bits/stdc++.h>
#define M 1000009
using namespace std;
int read(){
int f=1,re=0;char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<1)+(re<<3)+ch-'0';
return re*f;
}
const int inf=1e9+7;
int pri[M],v[M],num[M],cnt,ans=inf,n;
int nxt[M],first[M],to[M],tot,dep[M];
void init(){
for(int i=2;i<=1e6;i++){
if(!v[i]) v[i]=i,pri[++cnt]=i;
for(int j=1;j<=cnt;j++){
if(i*pri[j]>1e6||v[i]<pri[j]) break;
v[i*pri[j]]=pri[j];
}
}return;
}
void add(int x,int y){
nxt[++tot]=first[x],first[x]=tot,to[tot]=y;
nxt[++tot]=first[y],first[y]=tot,to[tot]=x;
}
void check(int x){
int y=x,cnt1=0,d[5];
while(y>1){
num[v[y]]^=1;
y/=v[y];
}y=x;
while(y>1){
if(num[v[y]]) d[++cnt1]=v[y];
num[v[y]]=0,y/=v[y];
}if(!cnt1){printf("1\n");exit(0);}
if(cnt1==1) add(1,d[1]);
else add(d[1],d[2]);
}
void solve(){
pri[0]=1;
//printf("%d\n",cnt);
for(int i=0;i<=cnt;i++){
if(pri[i]>1000) break;
memset(dep,-1,sizeof(dep));
queue<pair<int,int> >q;
q.push(make_pair(pri[i],0));
dep[pri[i]]=0;
//printf("%d\n",i);
while(q.size()){
int u=q.front().first,fa=q.front().second;
q.pop();
for(int j=first[u];j;j=nxt[j]){
int v1=to[j];
if(v1==fa) continue;
if(dep[v1]>=0) ans=min(ans,dep[u]+dep[v1]+1);
else dep[v1]=dep[u]+1,q.push(make_pair(v1,u));
}
}//printf("%d\n",ans);
}if(ans!=inf) printf("%d\n",ans);
else printf("-1\n");
return;
}
int main(){
init();
n=read();
for(int i=1;i<=n;i++){
int x=read();
check(x);
}
//for(int i=1;i<=tot;i+=2) printf("%d %d\n",to[i],to[i+1]);
//for(int i=1;i<=20;i++) printf("%d\n",v[i]);
solve();
return 0;
}