题目大意:

题目链接:​​https:///senior/#main/show/5791​

题目图片:

​http://wx2.sinaimg.cn/mw690/0060lm7Tly1fvxbuy446bj30j608kglm.jpg​

​http://wx3.sinaimg.cn/mw690/0060lm7Tly1fvxbuy44q9j30j40bbt8r.jpg​

给出nnn个数a[1],a[2]...a[n]a[1],a[2]...a[n]a[1],a[2]...a[n],求a[1]×a[2]×...×a[n]a[1]\times a[2]\times ...\times a[n]a[1]×a[2]×...×a[n]是m!m!m!因数的最小的mmm。


思路:

首先,我们可以把这nnn个数分解质因数,并将每个质因数存在一个桶里。

那么我们设分解后有k[1]k[1]k[1]个x[2]x[2]x[2],k[2]k[2]k[2]个x[2]...k[m]个x[m]x[2]...k[m]个x[m]x[2]...k[m]个x[m],那么原本的a[1]×a[2]×...×a[n]a[1]\times a[2]\times...\times a[n]a[1]×a[2]×...×a[n]就变成了:

x[1]k[1]×x[2]k[2]×...×x[m]k[m]x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]}x[1]k[1]×x[2]k[2]×...×x[m]k[m]

其实也就是说,​​将m!分解质因数后一定含有k[1]个x[1],k[2]个x[2],一直到k[m]个x[m]​​。

我们知道,如果m!m!m!分解质因数后含有x[1]k[1]×x[2]k[2]×...×x[m]k[m]x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]}x[1]k[1]×x[2]k[2]×...×x[m]k[m],那么(m+1)!(m+1)!(m+1)!就一定含有x[1]k[1]×x[2]k[2]×...×x[m]k[m]x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]}x[1]k[1]×x[2]k[2]×...×x[m]k[m]。

原因很简单。

证:
设T=x[1]k[1]×x[2]k[2]×...×x[m]k[m]T=x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]}T=x[1]k[1]×x[2]k[2]×...×x[m]k[m],那么由于m!m!m!分解质因数后含有TTT,那么m!m!m!就可以写成TxTxTx,其中xxx为正整数。
由于
(m+1)!=m!×(m+1)=Tx(m+1)(m+1)!=m!\times (m+1)=Tx(m+1)(m+1)!=m!×(m+1)=Tx(m+1)
所以(m+1)!(m+1)!(m+1)!就一定含有x[1]k[1]×x[2]k[2]×...×x[m]k[m]x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]}x[1]k[1]×x[2]k[2]×...×x[m]k[m]
证毕。

所以,也就是说,m!m!m!里含有的因式(m+1)(m+1)(m+1)一定含有,那么(m+2)(m+2)(m+2)也含有,(m+3)(m+3)(m+3)也含有。。。

所以,这个阶乘很明显是单调的。

那么就可以二分答案qqq。若q!q!q!含有k[1]k[1]k[1]个x[1]x[1]x[1],k[2]k[2]k[2]个x[2]...k[m]x[2]...k[m]x[2]...k[m]个x[m]x[m]x[m],那么q!q!q!就是合法的解,由此又可以得到大于qqq的数的阶乘也是合法的解。所以最小的答案就在[1,q][1,q][1,q]中。

否则就在[q+1,MAXN][q+1,MAXN][q+1,MAXN]中。

MAXNMAXNMAXN的话设大一点就好了。反正二分又不会很多次。

时间复杂度:O(nn+nlogn)O(n\sqrt{n}+nlogn)O(nn​+nlogn)


代码:

#include <cstdio>
#include <cmath>
#define ll long long
#define N 5000100
using namespace std;

int n,m,l,r,mid,num[N];

bool check(int x)
{
int sum;
ll y;
for (int i=2;i<=N;i++)
{
if (!num[i]) continue;
sum=0;
y=(ll)i;
while (y<=(ll)x)
{
sum=sum+(x/(int)y); //记录有多少个i
if (sum>num[i]) break;
y*=i;
}
if (sum<num[i]) return false; //不够
}
return true;
}

int main()
{
scanf("%d",&n);
int x;
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
for (int j=2;j*j<=x;j++)
while (!(x%j))
{
num[j]++; //分解质因数
x/=j;
}
if (x>1) num[x]++;
}
l=1;
r=N-1;
while (l<=r)
{
mid=(l+r)/2;
if (check(mid)) r=mid-1;
else l=mid+1;
}
printf("%d\n",r+1);
return 0;
}