[题解] 完美数


题目大意

给定 \(n\) 个数字,将这 \(n\) 个数字乘起来。找到 \(1\) 个数字 \(k\) ,使得 \(k!\) 能被 \(n\) 整除。求最小的 \(k\) 。

思路

先将 \(n\) 个数字分别质因数分解,用桶 \(B1\) 把这些质因数的个数统计起来。

按照题目的意思,需要找到一个 \(k!\) ,将其质因数分解,也把分解的这些质因数装进另一个桶 \(B2\) 里,使得桶 \(B2\) 里所有元素的个数都大于桶 \(B1\) 里面所有元素的个数。

怎么来找这个桶呢?可以二分枚举,找出答案。

这里分享另一种做法。

对于桶里面的每一个元素,都可以找到 \(1\) 个最小满足含有这个元素的乘积的倍数。描述有一些模糊,举个例子:

有 \(2\) 个数字,\(81\) 和 \(45\)。将这两个数字分解,则桶 \(B1\) 里,\(3\) 的个数为 \(6\) ,\(5\) 的个数为 \(1\) 。则最小满足 \(6\) 个 \(3\) 的数字为 \(15\)。其中, \(3\) 做 \(1\) 个贡献, \(6\) 做 \(1\) 个贡献, \(9\) 做 \(2\) 个贡献, \(12\) 做 \(1\) 个贡献, \(15\) 做 \(1\) 个贡献。简单来说,这个数字含有多少个 \(3\) ,就做多少贡献。可以直接暴力枚举,枚举到满足条件即可,这个数据枚举到 \(15\) 。对于 \(5\) 同理,枚举到 \(5\) 即可。最后取这两个数的最大值,因为 \(15!\) 就包含了 \(5!\) ,而且两质数之间互不干扰,没有交集。故而答案为 \(15\)。

总结

先用桶存储这 \(n\) 个数字的质因数个数,找桶中每个元素,满足这个元素的最小的 \(k\) ,取最大值来满足条件即可。

C++代码

#include 
#define Max(a, b) ((a) > (b) ? (a) : (b))
void Quick_Read(int &N) {
	N = 0;
	int op = 1;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-')
			op = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		N = (N << 1) + (N << 3) + (c ^ 48);
		c = getchar();
	}
	N *= op;
}
const int MAXN = 1e5 + 5;
int bucket[MAXN];
bool flag[MAXN], vis[MAXN];
int p[MAXN];
int n, cnt, num;
void Primes() {
	int k = 100000;
	flag[1] = 1;
	for(int i = 2; i <= k; i++) {
		if(!flag[i])
			p[++cnt] = i;
		for(int j = 1; p[j] * i <= k && j <= cnt; j++) {
			flag[p[j] * i] = true;
			if(i % p[j] == 0)
				break;
		}
	}
}
int main() {
	int A;
	Primes();
	Quick_Read(n);
	for(int i = 1; i <= n; i++) {
		Quick_Read(A);
		for(int j = 1; j <= cnt && A != 1; j++) {
			if(A <= 100000 && !flag[A])
				break;
			while(A % p[j] == 0) {
				A /= p[j];
				bucket[p[j]]++;
				if(!vis[p[j]])
					num++;
				vis[p[j]] = true;
			}
		}
		if(!vis[A] && A != 1)
			num++;
		vis[A] = true;
		bucket[A]++;
	}
	int ans = 0;
	for(int i = 2; i <= 100000; i++) {
		if(!bucket[i])
			continue;
		int j = 0, product, maxn = 0;
		while(bucket[i] > 0) {
			j++;
			product = j * i;
			while(product % i == 0) {
				product /= i;
				bucket[i]--;
			}
			maxn++;
		}
		ans = Max(ans, maxn * i);
	}
	printf("%d", ans);
	return 0;
}