题目大意
给定n个正整数分别为 a 1 , a 2 . . . . . a n a_1,a_2.....a_n a1,a2.....an,问至少删掉多少个数可以使得当前数的最大公因数会大于最初n个正整数的最大公因数
思路分析
首先我们可以得到最初
n
n
n个数的
g
c
d
gcd
gcd为
d
d
d,然后将原数组全部除以
d
d
d,即对于所有的
1
≤
i
≤
n
1 \leq i \leq n
1≤i≤n,都有
s
i
=
a
i
/
d
s_i=a_i/d
si=ai/d
很明显,现在
g
c
d
(
s
1
,
s
2
.
.
.
.
s
n
)
=
1
gcd(s_1,s_2....s_n)=1
gcd(s1,s2....sn)=1,此时,我们只需要删掉几个数使得
g
c
d
(
s
1
,
s
2
,
.
.
.
.
.
s
n
)
>
1
gcd(s_1,s_2,.....s_n)>1
gcd(s1,s2,.....sn)>1即可。
此时,如果尝试直接求要删掉的最小数量有点困难(也可能是我菜,悲),但是我们可以反过来考虑,尝试求出剩下来的数的最大数量是可行的,我们只要尝试枚举
s
i
s_i
si的约数,比如所有为2的倍数的个数,求出最大值然后再用
n
n
n减去便可。我们设
m
a
=
m
a
x
(
s
1
,
s
2
.
.
.
.
s
n
)
ma=max(s_1,s_2....s_n)
ma=max(s1,s2....sn),很明显约数的范围在
[
1
,
m
a
]
[1,ma]
[1,ma]中。在这里我们可以用质数枚举一下,对于区间中不范围的数(除了1),它对应的值已经在枚举它的质因子的过程中,已经被用过了,所以可以直接用线性筛筛出
[
1
,
m
a
]
[1,ma]
[1,ma]中的质数,然后用质数枚举即可,具体可参照代码
参考代码
void oula(int n)
{
for(int i=2;i<=n;i++)
{
if(!vis[i])
{
prime[cnt++]=i;
}
for(int j=0;i*prime[j]<=n;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
int num[N];
inline int gcd(int a,int b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
void solve()
{
int n;
cin>>n;
int d=0;
for(int i=1;i<=n;i++) cin>>s[i],d=gcd(d,s[i]);
int ma=-1;
for(int i=1;i<=n;i++)
{
s[i]=s[i]/d;
num[s[i]]++;
ma=max(s[i],ma);
}
oula(ma);
int ans=0;
//cout<<cnt<<endl;
for(int i=0;i<cnt;i++)
{
int sum=0;
for(int j=prime[i];j<=ma;j+=prime[i])
{
sum+=num[j];
}
if(sum>0)
{
ans=max(ans,sum);
}
}
if(ans==0) cout<<-1<<endl;
else cout<<n-ans<<endl;
}