【NOIP】普及组2009 细胞分裂

【算法】数论

【题解】均分的本质是A整除B,A整除B等价于A的质因数是B的子集

1.将m1分解质因数,即m1=p1^a1*p2^a2*...*pk^ak

所以M=m1^m2=p1^(a1*m2)*p2^(a2*m2)*...*pk^(ak*m2)

2.如果s[i](细胞初始个数)不能被M分解出来的质因数(即p1,p2...pn)中的某一个整除的话,这种细胞就永远不可能装入M个瓶子中

换句话说,如果s[i]分解出来的质因数不能包含M的所有质因数的话,就永远不能整除M(即使乘方(分裂)后)。

当然并不需要真的把s[i]分解为质因数,只要有一个s[i]%pj(j=1..k)!=0就说明是-1。

3.确定不是-1后,需要计算最小分裂时间。

当s[i]^ans中包含的每个pi的个数(假设为bi)比M中包含的pi的个数(即ai*m2)多时,就能被M整除。

所以就是找到最小的ans,使每个bi>=(ai*m2)(i=1...n)。

这个ans=ceil(a[i]*m2/b[i]) (只适用于a[i]*m2比b[i]大时)(ceil表示向上取整)

在所有s[i]中寻找最小的ans就是答案。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cctype>
using namespace std;
const int maxm=30010,maxn=10010,inf=0x3f3f3f3f,eps=1e-6;
int pri[maxm],num[maxm],num2[maxm],s[maxn],tot=0,n,m,m2,ans;
int main()
{
//    freopen("cell.in","r",stdin);
//    freopen("cell.out","w",stdout);
    scanf("%d",&n); scanf("%d%d",&m,&m2);
    for(int i=2;i*i<=m;i++)
     if(m%i==0)
      {
        pri[++tot]=i;
        while(m%i==0)m/=i,num[tot]++;
      } 
    if(m!=1)pri[++tot]=m,num[tot]=1;
    for(int i=1;i<=tot;i++)num[i]*=m2;
    ans=inf;//for(int i=1;i<=tot;i++)printf("[%d]%d %d\n",i,pri[i],num[i]);
    for(int i=1;i<=n;i++)
     {
         scanf("%d",&s[i]);
         int f=0;
         memset(num2,0,sizeof(num2));
         for(int j=1;j<=tot;j++)
          if(s[i]%pri[j]!=0)f=1;
         if(f)continue;
         for(int j=1;j<=tot;j++)
          while(s[i]%pri[j]==0)
           num2[j]++,s[i]/=pri[j];
         int maxs=0;
         for(int j=1;j<=tot;j++)
          if(num[j]>num2[j])//printf("[%d]num=%d,num2=%d\n",j,num[j],num2[j]),
           maxs=max(maxs,(int)(ceil(1.0*num[j]/num2[j])+eps));
//         printf("%d\n",maxs);
         ans=min(ans,maxs);
     }
    if(ans==inf)ans=-1;
    printf("%d",ans);
    return 0;
}
View Code

 

posted @ 2016-08-12 21:15  ONION_CYC  阅读(728)  评论(0编辑  收藏  举报