题解:首先以$1$为根,然后一步一步往下走寻找重心。如果某个子节点对应的子树内的特殊点的数量$x$满足$x \ge n-x$,那么往下走可以保证答案不会变差。而且注意到对于某一个节点,如果存在这样的子节点,那么是它唯一的,如果不存在,选择该点所得到的答案就是最优的,因为我们每一步都是选择的最优方案。因此我们现在只需要知道如何获取某个子树中有多少个特殊点,可以看出如果$a$是$b$的后代,那么组成$b$的所有质因子也是$a$的质因子,而且它们是$a$最大的质因子,也就是说当前点所代表的质因子序列,所有符合条件的点的质因子序列的一个后缀,按照这个性质进行维护即可。
#include <bits/stdc++.h>
#define maxn 5086
using namespace std;
typedef long long ll;
int n;
int a[maxn], b[maxn];
int p[maxn], cnt;
bool tag[maxn];
int x;
int f[maxn][maxn], num[maxn], g[maxn];
ll ans;//debug:n有1e6 不开ll见祖宗
int main(){
for(int i = 2;i <= 5000;i++){
if(!tag[i]) p[++cnt] = i;
for(int j = 1;j <= cnt && p[j] * i <= 5000;j++){
tag[p[j] * i] = true;
if(i % p[j] == 0) continue;
}
}
for(int i = 2;i <= 5000;i++){
x = i, memcpy(f[i], f[i - 1], sizeof(f[i - 1])), num[i] = num[i - 1], g[i] = g[i - 1];
for(int j = 1;x != 1 && j <= cnt;j++){
while(x % p[j] == 0) f[i][j]++, num[i]++, g[i] = max(g[i], j), x /= p[j];
}
}
scanf("%d", &n);
for(int i = 1;i <= n;i++) scanf("%d", &x), ++a[x];
for(int i = 1;i <= 5000;i++){
ans += 1ll * a[i] * num[i];
b[g[i]] += a[i];
//printf("%d %d--\n", a[i], g[i]);
}
//printf("%d--\n", ans);
while(1){
bool suc = false;
for(int i = 1;i <= cnt;i++){
if(b[i] >= n - b[i]){
//printf("%d %d--\n", p[i], b[i]);
suc = true;
ans -= b[i] - (n - b[i]);
for(int j = 1;j <= 5000;j++){
if(g[j]){
if(g[j] == i){
f[j][i]--;
if(!f[j][i]){
b[i] -= a[j];
while(!f[j][g[j]] && g[j]) --g[j];
if(g[j]) b[g[j]] += a[j];
}
}else{
b[g[j]] -= a[j], g[j] = 0;//debug:b[g[j]]打成b[i]
}
}
}
break;
}
}
if(!suc) break;
}
printf("%lld", ans);
}