CF1034A 题解
思路
先对 \(a_i\) 求 \(\operatorname{gcd}\)。\(g\) 表示数组的 \(\operatorname{gcd}\)。
每个 \(a_i\) 除以 \(g\)。要找出一个质数,使得有最多的除以 \(g\) 后的 \(a_i\) 整除该质数。对 \(a_i\) 做质因数分解,舍去重复的质数因子,加入桶中。最后枚举答案 \(ans=\min {n-t_i}\),\(n-t_i\) 即要删除的数的个数。
对 \(\max a_i\) 内的质数做素数筛,复杂度 \(O(a_i)\)。在素数筛向后转移的同时,标记 \(vis_{i\times pre_j}\) 为 \(1\) 时,记录 \(f_{i\times pre_j}=pre_j\),即 \(i\times pre_j\) 有一个质因数 \(pre_j\)。对 \(x\) 做质因数分解时,\(x\) 不断除以 \(f_x\) 直到 \(x=1\)。在分解过程中,所有的 \(f_x\) 即 \(x\) 的质因数。因为 \(a_i\) 最多有 \(\log a_i\) 质因子,所以总复杂度 \(O(n\log a_i+a_i)\),可以接受。
code
int n,a[maxn],g,ans=inf,mx;
bool vis[maxm];
int pre[maxn],cnt;
int f[maxm],t[maxm];
void s(int n){
for(int i=2;i<=n;i++){
if(!vis[i]){
pre[++cnt]=i;
f[i]=i;
}
for(int j=1;j<=cnt&&i*pre[j]<=n;j++){
f[i*pre[j]]=pre[j];
vis[i*pre[j]]=1;
if(i%pre[j]==0)break;
}
}
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
if(i==1)g=a[1];
else g=__gcd(g,a[i]);
}
for(int i=1;i<=n;i++){
a[i]/=g;
mx=max(mx,a[i]);
}
s(mx);
for(int i=1;i<=n;i++){
int lst=0;
while(a[i]!=1){
if(lst!=f[a[i]]){
lst=f[a[i]];
t[lst]++;
}
a[i]/=f[a[i]];
}
}
for(int i=1;i<=mx;i++)ans=min(ans,n-t[i]);
if(ans==n)printf("-1\n");
else printf("%d\n",ans);
}