Description
给你 (n) 个数,去掉尽量少的数使得剩下数的最大公约数比原来的大。无解输出 (-1)。
Solution
首先将所有数除以最大公约数
设 (M=max a_i),维护一个桶 (b[]),对每个 (i),在 (b[a[i]]) 处 (+1)
枚举 ([1,M]) 中的所有质数 (p),考虑让最大公约数乘以 (p),代价就是我们需要删去所有的 (a_i) 满足 (p|a_i),于是我们枚举所有 (p) 的整数倍 (q),统计所有 (b[q]) 的和,就是 (p) 的答案
最后对所有 (p) 的答案取最小值即可
复杂度是 (sum_{p leq M} M/i),由于收敛较快,可以接受
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 16000005;
int prime[MAXN+1];
void presolve() {
memset(prime,0,sizeof prime);
for(int i=2;i<=MAXN;i++) {
if(!prime[i]) prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++) {
prime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
const int N = 1000005;
int n,a[N],b[MAXN];
signed main() {
ios::sync_with_stdio(false);
presolve();
cin>>n;
int g=0;
for(int i=1;i<=n;i++) cin>>a[i], g=__gcd(g,a[i]);
for(int i=1;i<=n;i++) a[i]/=g;
for(int i=1;i<=n;i++) b[a[i]]++;
int M = *max_element(a+1,a+n+1);
int ans = 2e9;
for(int i=1;prime[i]<=M;i++) {
int p=prime[i];
int sum=0;
for(register int q=p;q<=M;q+=p) {
sum+=b[q];
}
ans=min(ans,n-sum);
}
cout<<(ans>1e9?-1:ans)<<endl;
}