题目大意
给定 (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 <cstdio>
#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;
}