题目大意:给出k个a1,a2...ak(1<=k<=10^10),求最小的n,使得n!被a1!*a2!*...*ak!整除;
思路:素数打表,minfact[i]表示i的最小素因子,big[i]表示假如最大为i,则i的数目,从大往小推(如果小到大会超时),如果素数就记录下来,如果是合数就往下推,
最后用二分把答案搜出来。
#include <cmath>
#include <stdio.h>
#include <algorithm>
#include <ctime>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define REP(i,n) for(int i=0;i<n;++i)
#define maxn 10000010
#define maxP 7000000
#define mset(a) memset(a,0,sizeof a)
#define FR(a) freopen(a,"r",stdin)
#define FW(a) freopen(a,"w",stdout)
const ULL INF = (1LL<<63)-1;
#define MOD 1000000007
int prime[maxn];
bool b[maxn];
int cnt=0;
int minfact[maxn];
ULL big[maxn];
int a[maxn];
void init()
{
cnt=1;
for(int i=2;i<maxn;++i)
if(!b[i])
{
prime[cnt++]=i;
for(int j=i*2;j<maxn;j+=i)
{
if(!minfact[j])
minfact[j]=i;
b[j]=1;
}
}
}
bool cmp(int a,int b)
{
return a>b;
}
int check(ULL n,int maxfact)
{
int i=1;
ULL m=n;
while (prime[i]<=maxfact&&prime[i]!=0)
{
n=m;
ULL ans=0;
while (n)
{
ans+=n/prime[i];
n/=prime[i];
}
if(ans<big[prime[i]])
return -1;
i++;
}
return 1;
}
int main()
{/*
FW("read.txt");
for(int i=0;i<100000;++i)
cout<<10000000<<' ';*/
//FR("read.txt");
init();
int k;
while (~scanf("%d",&k))
{
int maxfact=0;
mset(big);
REP(i,k)
scanf("%d",a+i);
sort(a,a+k,cmp);
int m=0;
for(int i=a[m++];i>1;--i)
{
while (i==a[m]&&m<k)
m++;
big[i]+=m;
if(b[i])
{
big[i/minfact[i]]+=big[i];
big[minfact[i]]+=big[i];
}
else maxfact=max(maxfact,i);
}
ULL ans=0;
ULL l=1,r=INF;
while (l<=r)
{
ULL mid=(l+r)>>1;
int x=check(mid,maxfact);
if(x>0)
r=mid-1;
else l=mid+1;
}
if(!ans)
ans=l;
printf("%I64u\n",ans);
}
}