D- 细胞分裂
题意:
输入 n,表示有n种细胞,数量为S-i,每秒分裂一次,每次分裂后的数量为原来的S-i倍。输入m1,m2,m1^m2表示试管个数。输入n种细胞最初始状态下的数量S-i。求哪一种细胞,经过最短的天数后,能过均匀的分布在所有试管中。输出最短天数。
解题思路:
由于由于级数过大。可以考虑质因数分解做法。将m1质因数分解,并保存所有质因数的个数与m2相乘的结果。m1m2即等于,所有m1所有质因数(个数*m2)的乘积。
同理,将细胞初始状态数,进行质因数分解,并记录每一个质因数的个数。
两个数相除,即是,所有 被除数质因数^(被除数的质因数的指数-除数质因数的指数)的乘积。
所以易知道,要使得能过均匀分布,即是能整除,即是相除后,被除数质因数的指数为非负整数即可。具体实现与细节请看代码注释。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m1,m2,s,a[30100],b[30100],max_,min_=INT_MAX-1,pos_,pos,d;
void zhi(int m,int a[]){//质因数分解。
if(m<=1)return ;
int flag=0;
for(int i=2;i<=m&&i<=30000;i++){// m1<=30000,所以i<=30000;
while(m!=i){
if(m%i==0){//若是质因数。
a[i]++;
m=m/i;
}
else break;
}
if(i==m)a[i]++;
pos_=max(i,pos_);//最大质数,用来确定后面遍历比较的上界。
}
}
int main(){
cin>>n;
cin>>m1>>m2;//总数为m1^m2
memset(a,0,sizeof(a));//初始化。
zhi(m1,a);//将底数m1质因数分解,记录某个因数的个数,并保存在数组a中。
pos=pos_;//最大因数,用于后面循环遍历的上界
for(int i=0;i<=pos;i++){
a[i]*=m2;//由于是m1^m2,所以,即使有m2个m1相乘,则将每个因数的个数乘以m2.
}
int flag=0,n_=n;
while(n--){//输入n个数
int flag2=0;
memset(b,0,sizeof(b));//初始化b数组。
max_=1;
cin>>s;
zhi(s,b);//将最初的倍数s质因数分解,记录每一个因数的个数,并保存在数组b中。
for(int i=2;i<=pos+1;i++){
if(a[i]!=0&&b[i]==0){//如若,最初倍数s的因数中没有m1^m2的因数相对应,则永远除不尽。直接跳出循环
flag++;
flag2=1;
break;
}else if(a[i]==0&&b[i]==0||(a[i]<=b[i])){//s与m1^m2都无此质因数。直接跳过。
continue;
}
d=a[i]/b[i]+(a[i]%b[i]!=0);//向上取整。
max_=max(d,max_);//维护最大值,即最大满足条件。
}
if(flag2!=1)min_=min(min_,max_);//维护最大值的最小值。
}
if(m1==1){//特殊情况
cout<<0<<endl;
return 0;
}
if(flag==n_)cout<<-1<<endl;//若全都不能除尽,则输出-1
else cout<<min_<<endl;//输出最小值。
}