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;
}