P1069 [NOIP2009 普及组] 细胞分裂 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
唯一分解定理:任意一个大于1正整数X,都可以表示为若干个质数的乘积(质因数)
本题我们得知试管数是m2个m1相乘,非常大,直接算是不现实的,我们可以先将m1做质因数分解,记录其质因数,并且记录其质因数个数,然后m2个m1,就直接将质因数个数都乘上m2即可。
然后,我们对每个细胞分裂1s的值(也就是Si)都除以试管的质因子,如果Si能整除每一个试管的质因子,就说明该Si,可经过分裂后变为试管的倍数,就是可以整除试管,但是如果不能整除试管的每一个质因子,那么分裂几次都没用。
然后我们在所有可以分裂成试管的Si值中挑选分裂时间最短的那个,就是答案。
怎么计算分裂时间呢?
举个题目的样例:
2 24 1 30 12
试管数:24=2³*3
S1:30=2*3*5再裂一次 2*2*3*3*5*5 两次无法成为24的倍数
S2:12=2²*3 再裂一次 2³*3*2*3 已经称为24的倍数,时间是2s
所以计算时间的方法就是拿试管质因数的个数,除以Si对应质因数的个数,注意应当向上取整。
然后在所有结果中挑一个最大的,才能代表细胞分裂达到要求的时间
说还是比较复杂具体看代码!!
ACcode:
#include <iostream>
#include <vector>
#include <cstring>
#include <cmath>
using namespace std;
const int N=1e4+10;
int n,m1,m2;
int ans=0x3f3f3f3f;
int s[N];
vector<int> prime;//试管质因数
vector<int> count;//试管质因数次数
int main()
{
cin>>n>>m1>>m2;
if(pow(m1,m2)==1) {cout<<"0"; return 0;} //如果只有一个试管,就不用分
for(int i=1;i<=n;i++) cin>>s[i];
for(int i=2;i<=m1/i;i++)
{
if(m1%i) continue;
int x=i;
int cnt=0;
while(m1%i==0){ //把这个质因子除干净
m1/=i;
cnt++;
}
prime.push_back(x);
count.push_back(cnt);
}
if(m1>1){ //m1还没有除干净,那他自己就是最大的质因子
prime.push_back(m1);
count.push_back(1);
}
for(int i=0;i<prime.size();i++) count[i]*=m2;//因为有m2个m1,所以次数要乘上
for(int i=1;i<=n;i++)
{
int j;
for(j=0;j<prime.size();j++)
{
if(s[i]%prime[j]!=0) break;//不包含这个质因子,分裂几次都没用
}
if(j!=prime.size()) continue;
//能到这里说明包含了全部的质因子,可以算时间了
//对S[i]计算其质因数个数
int time=-1;//记录分裂几次,能满足试管分配
for(int k=0;k<prime.size();k++)
{
int cnt=0;
while(s[i]%prime[k]==0)//把这个质因子除干净
{
s[i]/=prime[k];cnt++;
}
int spend=ceil(1.0*count[k]/cnt);//分裂时间要向上取整
time=max(time,spend);//这个得取一个最大的
}
ans=min(time,ans);
}
if(ans==0x3f3f3f3f) cout<<"-1";
else cout<<ans;
return 0;
}