hdu3988 Harry Potter and the Hide Story(數論-勒讓德定理-質因子分解)
阿新 • • 發佈:2019-01-12
題意
給出一個n,一個k,求k的最大次方ans,能被n!整除
思路來源
http://www.cnblogs.com/toyking/p/3893157.html
題解
先預處理1e7以內的素數,O(nlognlogn)
每個k,對素數表裡跑一遍,
這樣素數列舉的時候,O(T·cnt),就不是O(T·sqrt(k))了
剩下的操作,和今晚的上個題相同(見上篇UVA-10780),
就是資料量大了點。
心得
這題WA了五發,心態爆炸……
①int i*i可能爆int,埃氏篩法改了一發
②ans可能大於1e18,令n=1e18,k=2即可,但這種情況也不會超過2e18
因此將ans至少初始化為2e18,只有k=1的情況是inf
③unsigned long long,後來證明沒必要,不會爆1e19
④迴圈i*=t的時候可能爆ll,所以改成從n向下除
⑤開始把n和k的順序搞反了
⑥prime陣列只開了1e5,後來擴容開到1e6,後來證明沒必要
⑦map整數列舉的時候,prime[i]>n了直接break跳出,能將時間從4960ms縮到1760ms
程式碼風格還是太辣雞,各種出小錯。
程式碼
#include <iostream> #include <cstdio> #include <cstring> #include <map> const int maxn=1e7+10; const int maxm=1e5+10; using namespace std; typedef long long ll; bool notprime[maxn]; ll cnt,prime[maxm]; int t; void init() { for(ll i=2;i<maxn;++i) { if(notprime[i])continue; prime[cnt++]=i; for(ll j=i*i;j<maxn;j+=i)//i*i可能爆int notprime[j]=1; } } map<ll,ll>q; map<ll,ll>fac(ll n) { map<ll,ll>res; for(int i=0;i<cnt;++i) { if(prime[i]>n)break; while(n%prime[i]==0) { ++res[prime[i]]; n/=prime[i]; } } if(n!=1)res[n]=1; return res; } int main() { init(); scanf("%d",&t); for(int k=1;k<=t;++k) { ll n,m,cnt=0; ll ans=2e18; q.clear(); scanf("%lld%lld",&n,&m); printf("Case %d: ",k); if(m==1) { puts("inf"); continue; } q=fac(m); for(map<ll,ll>::iterator it=q.begin();it!=q.end();++it) { ll t=it->first,num=it->second,tmp=0; ll nn=n; while(nn>0) { tmp+=nn/t; nn/=t; } tmp/=num; ans=min(ans,tmp); } printf("%lld\n",ans);//0也輸出0 } return 0; }