题目大意:
题目链接:https://jzoj.net/senior/#main/show/5791
题目图片:
http://wx2.sinaimg.cn/mw690/0060lm7Tly1fvxbuy446bj30j608kglm.jpg
http://wx3.sinaimg.cn/mw690/0060lm7Tly1fvxbuy44q9j30j40bbt8r.jpg
给出个数,求是因数的最小的。
思路:
首先,我们可以把这个数分解质因数,并将每个质因数存在一个桶里。
那么我们设分解后有个,个,那么原本的就变成了:
其实也就是说,将m!分解质因数后一定含有k[1]个x[1],k[2]个x[2],一直到k[m]个x[m]
。
我们知道,如果分解质因数后含有,那么就一定含有。
原因很简单。
证:
设,那么由于分解质因数后含有,那么就可以写成,其中为正整数。
由于
所以就一定含有
证毕。
所以,也就是说,里含有的因式一定含有,那么也含有,也含有。。。
所以,这个阶乘很明显是单调的。
那么就可以二分答案。若含有个,个个,那么就是合法的解,由此又可以得到大于的数的阶乘也是合法的解。所以最小的答案就在中。
否则就在中。
的话设大一点就好了。反正二分又不会很多次。
时间复杂度:
代码:
#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;
}