IOI2021集训队作业 173QE Equal Numbers
给你\(n\)个数,每次可以将一个数乘任意正整数。对于\(k\in[0,n]\),求进行\(k\)次操作得到的数列中不同的数的最小值。
\(n\le 3*10^5\)
统计每个数的出现次数。将数分成两类:\(A\)类,存在另一个数为它的不为\(1\)的正整数倍;\(B\)类,不存在另一个数为它的不为\(1\)的正整数倍。
一种情况是\(B\)类数不动,于是每种\(A\)类数的代价是个数次操作,贡献是\(-1\)。
另一种情况是\(B\)类数动了。为了使\(B\)类数产生贡献,必须要钦定另一个数变成所有数的\(LCM\)。为了最优取出现次数最小的(\(A\)类或\(B\)类都行)。
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 300005
#define M 1000000
int n;
int buc[M+5];
int a[N],b[N];
int na,nb;
int f[N];
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&n);
for (int i=1;i<=n;++i){
int x;
scanf("%d",&x);
buc[x]++;
}
int cnt=0;
for (int i=M;i>=1;--i)
if (buc[i]){
cnt++;
bool bz=0;
for (int j=i+i;j<=M && !bz;j+=i)
if (buc[j])
bz=1;
if (bz==0)
b[++nb]=buc[i];
else
a[++na]=buc[i];
}
sort(a+1,a+na+1);
int s=0;
f[s]=0;
for (int i=1;i<=na;++i){
s+=a[i];
f[s]=max(f[s],i);
}
if (na+nb>=2){
for (int i=1;i<=nb;++i)
a[++na]=b[i];
sort(a+1,a+na+1);
s=a[1]+a[2];
f[s]=max(f[s],1);
for (int i=3;i<=na;++i){
s+=a[i];
f[s]=max(f[s],i-1);
}
for (int i=1;i<=n;++i)
f[i]=max(f[i-1],f[i]);
}
for (int i=0;i<=n;++i)
printf("%d ",cnt-f[i]);
return 0;
}