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;
}
posted @ 2020-10-16 08:28  jz_597  阅读(104)  评论(0编辑  收藏  举报