[NOIP2009普及組]細胞分裂
阿新 • • 發佈:2017-08-14
pre div urn cpp pri inline sdi ceil dev
題目:洛谷P1069、Vijos P1814、codevs1152。
題目大意:給你一個$m_1$和$m_2$,和n個數$s_i$,要你求這n個數中是否有一個數滿足$s_i ^t \equiv 0(mod\ m_1^{m_2})$,如果有則輸出最小的t,沒有輸出-1。
解題思路:由於$m_1^{m_2}$最大能達到$30000^{10000}$,直接判斷顯然是不可能的。
我們可以把$m_1$和$s_i$分解質因數,那麽就有$s_i ^t =p_1^{a_1}p_2^{a_2}...p_k^{a_k},m_1=q_1^{b_1}q_2^{b_2}...q_k^{b_k}$。
進而可以得出:$s_i^t=p_1^{ta_1}p_2^{ta_2}...p_k^{ta_k},m_1^{m_2}=q_1^{m_2b_1}q_2^{m_2b_2}...q_k^{m_2b_k}$。
如果$s_i$的若幹次方要是$m_1^{m_2}$的倍數,那麽它本身必須含有$m_1$的所有質因子,如果滿足這個條件,那麽對於相同的質因子,$\lceil \frac{b_km_2}{a_k}\rceil$就是所需的次數。這些次數的最大值就是t的答案。最終答案就是所有t的最小值。
此題只要分解質因數的效率不低,就不會超時,我之前就是因為分解質因數效率太低而TLE。
C++ Code:
#include<cstdio> #include<cstring> #include<cctype> using namespace std; struct prime{ int cnt,pn[30001],s[30001]; }p,q; inline int readint(){ char c=getchar(); while(!isdigit(c))c=getchar(); int p=0; while(isdigit(c))p=(p<<3)+(p<<1)+(c^‘0‘),c=getchar(); return p; } int n,m1,m2; void fenjie(int t,prime& p){ p.cnt=0; for(int i=2;i*i<=t;++i) if(!(t%i)){ p.pn[++p.cnt]=i; p.s[p.cnt]=0; do{ t/=i; ++p.s[p.cnt]; }while(!(t%i)); } if(t>1){ p.pn[++p.cnt]=t; p.s[p.cnt]=1; } } int main(){ n=readint(),m1=readint(),m2=readint(); if(m1==1){ puts("0"); return 0; } fenjie(m1,p); int ans=-1,x; while(n--){ x=readint(); fenjie(x,q); int mx=0,nxt=1; bool ok=false; if(q.cnt>=p.cnt) for(int i=1;i<=p.cnt;++i){ while(q.pn[nxt]<p.pn[i]&&nxt<=q.cnt)++nxt; if(nxt>q.cnt||q.pn[nxt]>p.pn[i])break; int f=p.s[i]*m2/q.s[nxt]; if(p.s[i]*m2%q.s[nxt])++f; if(mx<f)mx=f; ok=i==p.cnt; } if(ok&&(ans==-1||ans>mx))ans=mx; } printf("%d\n",ans); return 0; }
[NOIP2009普及組]細胞分裂