2019暑假集训 细胞分裂

题目描述

Hanks博士是 BT (BioTech,生物技术) 领域的知名专家。现在,他正在为一个细胞实验做准备工作:培养细胞样本。

Hanks 博士手里现在有 N种细胞,编号从 1-N,一个第 i种细胞经过 1 秒钟可以分裂为Si个同种细胞(Si为正整数)。现在他需要选取某种细胞的一个放进培养皿,让其自由分裂,进行培养。一段时间以后,再把培养皿中的所有细胞平均分入M个试管,形成M份样本,用于实验。Hanks 博士的试管数M很大,普通的计算机的基本数据类型无法存储这样大的M值,但万幸的是,M 总可以表示为m1m2次方,即M=m1^m2,其中 m1,m2均为基本数据类型可以存储的正整数。

注意,整个实验过程中不允许分割单个细胞,比如某个时刻若培养皿中有 4个细胞,

Hanks博士可以把它们分入 2 个试管,每试管内2 个,然后开始实验。但如果培养皿中有5个细胞,博士就无法将它们均分入2 个试管。此时,博士就只能等待一段时间,让细胞们继续分裂,使得其个数可以均分,或是干脆改换另一种细胞培养。

为了能让实验尽早开始,Hanks博士在选定一种细胞开始培养后,总是在得到的细胞“刚好可以平均分入 M个试管”时停止细胞培养并开始实验。现在博士希望知道,选择哪种细胞培养,可以使得实验的开始时间最早。

输入格式

第一行,有一个正整数 N,代表细胞种数。

第二行,有两个正整数m1,m2,以一个空格隔开,即表示试管的总数 M=m1m2.

第三行有 N 个正整数,第 i 个数 Si表示第 i 种细胞经过 1 秒钟可以分裂成同种细胞的个数。

输出格式

一个整数,表示从开始培养细胞到实验能够开始所经过的最少时间(单位为秒)。

如果无论Hanks博士选择哪种细胞都不能满足要求,则输出整数-1

输入输出样例

输入 #1
1 
2 1 
3
输出 #1
-1
输入 #2
2
24 1
30 12
输出 #2
2

说明/提示

【输入输出说明】

经过 1秒钟,细胞分裂成3 个,经过2秒钟,细胞分裂成9个,……,可以看出无论怎么分裂,细胞的个数都是奇数,因此永远不能分入 2个试管。

【输入输出样例22说明】

第 1 种细胞最早在3秒后才能均分入24个试管,而第2 种最早在2 秒后就可以均分(每试管144/(241)=6 个)。故实验最早可以在2 秒后开始。

【数据范围】

对于 50%的数据,有m1^m230000。

对于所有的数据,有1N10000,1m130000,1m210000,1Si2,000,000,000。

题目来自洛谷P1069/NOIP2009pj t3

话说再也没有NOIP了qwq


数学题,不解释。
其实本题可以转化为,对于每个给定的a以及给定的c,d,找到最小的b使得a^b|c^d。
由于没有要求a^b/c^d等于几,而整除的条件是每个质因数都能整除,我们对c进行分解质因数,并将每个质因数个数*d;
然后对这些质因数进行扫描,判断a是否能整除之,若不能,则不存在a^b|c^d;若能,设a中能分解出k个该质因数,c^d中能分解出k1个,则
对于每个a,其b=max((k1/k)向上取整)。
取max的原因是对于每个质因数都必须满足其数目大于c^d中该质因数数目;
k1/k向上取整的原因实质上是找到一个最小的q使得kq>k1.
上代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int prim[100050],book[100050],m1,m2,n,s[100050],idx,ans=0x3f3f3f3f;
int main()
{
    scanf("%d",&n);
    scanf("%d%d",&m1,&m2);
    for(int i=1;i<=n;i++)scanf("%d",&s[i]);
    for(int i=2;i<=m1;i++)
    {
        if(m1%i==0)
        {
            prim[++idx]=i;
            while(m1%i==0)
            {
                m1/=i;
                book[i]++;
            }
            book[i]*=m2;
        }
    }//预处理m1^m2质因数
    for(int i=1;i<=n;i++)
    {
        int anss=0,flag=0;
        for(int j=1;j<=idx;j++)
        {
            if(s[i]%prim[j]!=0)
            {
                flag=1;
                break;
            }//判断不可能
            int cnt=0,temp=s[i];
            while(temp%prim[j]==0)
            {
                temp/=prim[j];
                cnt++;
            }//扫描该细胞分裂数目中含有几个质因数i
            anss=max(anss,book[prim[j]]/cnt*cnt==book[prim[j]]?book[prim[j]]/cnt:book[prim[j]]/cnt+1);//后一步是手动向上取整,因为不想写ceil
        }
        if(flag)continue;//判断是否该细胞不可能
        ans=min(ans,anss);
    }
    if(ans==0x3f3f3f3f)puts("-1");//判断无解
    else printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qxds/p/11370719.html