JZOJ 5791 阶乘 —— 因数
题目:https://jzoj.net/senior/#main/show/5791
题意:有n个正整数a[i],设它们乘积为p,你可以给p乘上一个正整数q,使p*q刚好为正整数m的阶乘,求m的最小值。
对于10%的数据,n<=10
对于30%的数据,n<=1000
对于100%的数据,n<=100000,a[i]<=100000
首先,p * q = m!,也就是 p 是 m! 的一个因数;
把 p 质因数分解,那么 m! 的每个对应质因数的次数都 >= p 中对应质因数的次数;
不必乘出来 p,只要把每个 a[i] 质因数分解即可;
对于 m!,统计质因数的次数就是 cnt[i] += m / pri[i] , m /= pri[i],证明之类的很好想啦。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const maxn=1e5+5,inf=1e9; int n,a[maxn],p[maxn],ans,mx,pri[maxn],cnt; bool ck(int x) { if(x<mx)return 0; for(int i=2,t,tmp;i<=x&&i<=mx;i++) { if(!p[i])continue; t=0; tmp=x; while(tmp)t+=tmp/i,tmp/=i; if(t<p[i]){/*printf("t=%d p[%d]=%d\n",t,i,p[i]);*/ return 0;} // printf("x=%d t=%d p[%d]=%d\n",x,t,i,p[i]); } return 1; } int main() { freopen("factorial.in","r",stdin); freopen("factorial.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); for(int j=2;j*j<=a[i];j++) while(a[i]%j==0)p[j]++,a[i]/=j,mx=max(mx,j); if(a[i]>1)p[a[i]]++; mx=max(mx,a[i]); } int l=0,r=inf; while(l<=r) { int mid=((l+r)>>1); // printf("l=%d r=%d mid=%d ck=%d\n",l,r,mid,ck(mid)); if(ck(mid))ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans); return 0; }