题解 CF1034A 【Enlarge GCD】
Description
题目链接:Codeforces 1034A
Mr. F 现在有
他认为这些数的最大公因数太小了,所以他想通过删除其中的一些数来增大这个最大公因数。你的任务是计算出最少的需要删除的数的个数,使得删除之后剩余数的最大公约数大于删除之前的最大公约数。无解输出
数据范围:
Solution
朴素思路
对于最大公约数,我们可以模拟计算的过程,我们写出所有数字的质因子分解式,对于每个小于
那么要使得
但是我们并没有考虑大于
如果
由于小于
时间复杂度:
优化思路
我们发现,如果把
很自然地,我们想到可以枚举
由于质数的个数有
时间复杂度:
Code
朴素思路
#include <cstdio>
#include <cstring>
#include <map>
const int N=3e5+5;
int n,a[N],tot,p[N],mn[N],cnt[N],rcnt[N];
bool flg[N];
std::map<int,int> mp;
void sieve(int n) {
for(int i=2;i<=n;++i) {
if(!flg[i]) p[++tot]=i;
for(int j=1;j<=tot&&i*p[j]<=n;++j) {
flg[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
int getcnt(int &x,int p) {
int ans=0;
while(x%p==0) x/=p,++ans;
return ans;
}
void solve() {
memset(mn,0x3f,sizeof(mn));
int idx=0;
for(int i=1;i<=n;++i) {
for(int j=1;j<=tot;++j) {
int c=getcnt(a[i],p[j]);
if(mn[j]>c) mn[j]=c,cnt[j]=1;
else if(mn[j]==c) ++cnt[j];
}
if(a[i]>1) {
if(!mp[a[i]]) mp[a[i]]=++idx;
++rcnt[mp[a[i]]];
}
}
int ans=n;
for(int i=1;i<=tot;++i) ans=std::min(ans,cnt[i]);
for(int i=1;i<=idx;++i) ans=std::min(ans,n-rcnt[i]>0?n-rcnt[i]:n);
printf("%d\n",ans==n?-1:ans);
}
int main() {
sieve(4000);
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
solve();
return 0;
}
优化思路
#include <cstdio>
#include <algorithm>
const int N=3e5+5,M=1.5e7+5;
int n,tot,a[N],p[M/10],cnt[M];
bool flg[M];
void sieve(int n) {
for(int i=2;i<=n;++i) {
if(!flg[i]) p[++tot]=i;
for(int j=1;j<=tot&&i*p[j]<=n;++j) {
flg[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
int gcd(int x,int y) {
return y?gcd(y,x%y):x;
}
int main() {
scanf("%d",&n);
int d=0,mx=0;
for(int i=1;i<=n;++i) scanf("%d",&a[i]),d=gcd(d,a[i]);
for(int i=1;i<=n;++i) a[i]/=d,mx=std::max(mx,a[i]),++cnt[a[i]];
sieve(mx);
int ans=n;
for(int i=1;i<=tot;++i) {
int x=p[i],num=0;
for(int j=x;j<=mx;j+=x) num+=cnt[j];
if(num) ans=std::min(ans,n-num);
}
printf("%d\n",ans==n?-1:ans);
return 0;
}