题目链接:https://vjudge.net/contest/373416#problem/E
题意:给你n个数,目前的gcd值为g,问你最少去掉几个数可以使剩下的数的gcd值大于g。
思路:先把原数组中的数都除去g,然后再把除去这个数后的所有数进行因式分解,用一个num数组来记录一个因数在这个除去g的数组中共出现了几次,找到出现此次数最多的,然后用n减去它就行了。
Input
3
1 2 4
Output
1Input
4 6 9 15 30Output
2Input
3 1 1 1Output
-1
代码如下:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
int a[300010];
const int N = 15000010;
int book[N];
int su[N],num[N];
ll gcd(ll a,ll b)//最大公约数
{
return b?gcd(b,a%b):a;
}
int r=0;
void prime()//欧拉筛
{
memset(book,0,sizeof(book));
book[0]=1;
book[1]=1;
for(int i=2; i<N; i++)
{
if(book[i]==0)
{
su[r++]=i;
}
for(int j=0; j<r&&su[j]*i<N; j++)
{
book[i*su[j]]=1;
if(i%su[j]==0)
break;
}
}
}
int main()
{
prime();
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
int g=a[1];
for(int i=2; i<=n; i++)//得出原数组最大公约数
g=gcd(g,a[i]);
for(int i=1; i<=n; i++)
{
a[i]/=g;//原数组每个元素都除去g
for(int j=0; su[j]*su[j]<=a[i]; j++)//因式分解
{
if(a[i]%su[j]==0)
num[su[j]]++;//统计出现的因子个数
while(a[i]%su[j]==0)
a[i]/=su[j];
}
if(a[i]>1)
num[a[i]]++;
}
int ans=n;
for(int i=2; i<N; i++)
ans=min(ans,n-num[i]);//找出出现最多的
if(ans==n)
printf("-1\n");
else
printf("%d\n",ans);
return 0;
}