【2018/10/05】T1
阿新 • • 發佈:2018-12-13
我好菜啊……好菜啊……好菜啊……
階乘
(fact)【問題描述】 有 n個正整數 a[i],設它們乘積為 p,你可以給 p乘上一個正整數 q,使 p*q剛好為正整數m的階乘,求m的最小值。 【輸入】 共兩行。 第一行一個正整數n。 第二行n個正整數a[i]。 【輸出】 共一行 一個正整數m。 【輸入樣例】 1 6 【輸出樣例】 3 樣例解釋: 當p=6,q=1時,p*q=3! 【資料範圍與約定】 對於10%的資料,n<=10 對於30%的資料,n<=1000 對於100%的資料,n<=100000,a[i]<=100000
牢騷
我覺得我可能是把這道題想複雜了吧,反正我推了一個半小時,居然連一分都沒拿到手%>_<%,
思路離正解很近了,只是可能因為長時間耗在上面,思維固化了,就沒想出來程式碼該怎麼寫,以後還是別在一道題上吊死
主要還是不知道怎麼分解階乘的質因數
今天評講完後總算會了一點點了
先看一個簡單的問題: 27!裡面有多少個3相乘? 27!=1*2*...*27 包含1個3的數有27/(3^1)=9個 包含2個3的數有27/(3^2)=3個 包含3個3的數有27/(3^3)=1個 總共:9+3+1=13 個
所以27!裡面有13個3相乘。
具體程式碼實現呢大概也就是用一個while迴圈不停的除,然後累加即可
分析
首先根據標題 fact,我們就能八九不離十,猜出來要分解質因數了
然後可以把p分解質因數,假設 p=∏ai^bi(ai為質數),那麼只要 m!包含了每個ai^bi,m!就包含p。 所以就可以二分答案咯,因為m!這個是單增的
程式碼
#include<bits/stdc++.h> #define N 100000 #define in read() using namespace std; int n; inline int read(){ char ch;int f=1,res=0; while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1; while(ch>='0'&&ch<='9'){ res=(res<<3)+(res<<1)+ch-'0'; ch=getchar(); } return f==1?res:-res; } bool mark[N+10]; int pri[N+10],num=0; void init(){//線性篩素數 mark[1]=1; for(int i=2;i<=N;++i){ if(!mark[i]) pri[++num]=i; for(int j=1;j<=num&&i*pri[j]<=N;++j){ mark[i*pri[j]]=1; if(i%pri[j]==0) break; } } } int a,b[N],maxn=-1,c[N]; void fenjie(int x){//對p進行分解 int tmp; for(int i=1;i<=num&&pri[i]<=x;++i){ tmp=x; while(tmp%pri[i]==0){ tmp/=pri[i]; b[pri[i]]++; maxn=max(maxn,pri[i]); } } if(tmp) b[tmp]++; } int check(int m){//二分答案的檢驗 memset(c,0,sizeof(c)); int tmp; for(int i=1;i<=num&&pri[i]<=m;++i){ tmp=m; while(tmp){//就是這裡啦,階乘的分解質因數 c[pri[i]]=(c[pri[i]]+tmp/pri[i]); tmp/=pri[i]; } } for(int i=2;i<=maxn;++i) if(!mark[i]) if(b[i]>c[i]) return 0; return 1; } int main(){ n=in; init(); while(n--){ a=in; fenjie(a); } int l=1,r=1000000000,ans=0; while(l<=r){ int mid=l+r>>1; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } printf("%d",ans); return 0; }