当前位置 博文首页 > 文章内容

    [luogu p1069] 细胞分裂

    作者: 栏目:未分类 时间:2020-10-03 15:05:52

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    细胞分裂 题解

    传送门

    细胞分裂

    题目描述

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

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

    注意,整个实验过程中不允许分割单个细胞,比如某个时刻若培养皿中有\(4\)个细胞,\(Hanks\)博士可以把它们分入\(2\)个试管,每试管内\(2\)个,然后开始实验。但如果培养皿中有\(5\)个细胞,博士就无法将它们均分入\(2\)个试管。此时,博士就只能等待一段时间,让细胞们继续分裂,使得其个数可以均分,或是干脆改换另一种细胞培养。

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

    输入输出格式

    输入格式

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

    第二行,有两个正整数\(m_1,m_2\),以一个空格隔开,即表示试管的总数\(M = m_1^{m_2}\).

    第三行有 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\)个试管。

    【输入输出样例\(2\)说明】

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

    【数据范围】

    对于 50%的数据,有\(m_1^{m_2} ≤ 30000\)

    对于所有的数据,有\(1 ≤N≤ 10000,1 ≤m_1 ≤ 30000,1 ≤m_2 ≤ 10000,1 ≤ S_i ≤ 2,000,000,000\)

    NOIP 2009 普及组 第三题

    分析

    此题 \(M\) 非常大,因此如果你暴力满分我直接吃屏。观察一下题面,很显然能看出是一道数论。

    先抛弃最小值不谈,来对单独一个细胞进行分析。假设这个细胞分裂能力是 \(s\),那么我们要求的就是满足 \(s ^ t | M\)\(t\) 的最小值

    首先先将 \(s\)\(M\) 质因数分解。(\(m_1\) 中若含有 \(P\) 个质因数 \(p\),那么 \(M = m_1 ^ {m_2}\) 中就有 \(m_2P\) 个质因数 \(p\),因此\(m_1\) 质因数分解,然后对每个质因数数量乘上 \(m_2\) 即可。这也正是为什么 \(M\) 总能表示为 \(m_1 ^ {m_2}\) 的情形。)

    \(p\)\(s\)\(M\) 的一个共同质因数,\(s\) 中包含 \(s_p\)\(p\)\(M\) 中包含 \(M_p\)\(p\),那么若想让 \(s ^ t | M\),就必须满足 \(t \ge \left\lceil\dfrac{M_p}{s_p}\right\rceil\)。这样,枚举 \(p\),找到 \(\left\lceil\dfrac{M_p}{s_p}\right\rceil\) 的最大值,那么 \(t\) 值自然就是这个最大值了。

    什么时候无解呢?

    对于一个质数 \(p\),定义 \(s_p\)\(s\)\(p\) 因数的数量,\(M_p\)\(M\)\(p\) 因数的数量。若存在一个质数 \(p\),使得 \(s_p = 0\)\(M_p \ne 0\),那么不存在 \(t\) 使得 \(s ^ t | M\)

    最后,对每个 \(s\) 都进行上次的操作,在得到的 \(t\) 值中找到最小值即可。

    如果所有都是无解的,那么答案自然就是 \(-1\) 咯。

    上代码:

    代码

    /*
     * @Author: crab-in-the-northeast 
     * @Date: 2020-10-02 20:06:20 
     * @Last Modified by: crab-in-the-northeast
     * @Last Modified time: 2020-10-02 21:52:59
     */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <climits>
    
    const int maxm1 = 30005;
    
    int prime_num[maxm1], cnt;
    bool isprime[maxm1];
    
    void prime(int n) {
        std :: memset(isprime, true, sizeof(isprime));
        isprime[1] = false;
        for (int i = 2; i <= n; ++i) {
            if (isprime[i]) prime_num[++cnt] = i;
            for (int j = 1; j <= cnt && i * prime_num[j] <= n; ++j) {
                isprime[i * prime_num[j]] = false;
                if (i % prime_num[j] == 0) break;
            }
        }
    }
    
    int tube_prime[maxm1], cell_prime[maxm1];
    
    int main() {
        int n, m1, m2, ans = INT_MAX;
        std :: scanf("%d", &n);
        std :: scanf("%d %d", &m1, &m2);
    
        prime(30000);
        for (int i = 1, div = m1; div != 1; ++i) {
            while (div % prime_num[i] == 0) {
                tube_prime[i] += m2;
                div /= prime_num[i];
            }
        }
    
        for (int i = 1; i <= n; ++i) {
            int s, need = 0;
            std :: scanf("%d", &s);
            std :: memset(cell_prime, 0, sizeof(cell_prime));
            for (int j = 1, div = s; j <= cnt; ++j) {
                while (div % prime_num[j] == 0) {
                    ++cell_prime[j];
                    div /= prime_num[j];
                }
            }
    
            bool valid = true;
            for (int j = 1; j <= cnt; ++j) {
                if (tube_prime[j] != 0 && cell_prime[j] == 0) {
                    valid = false;
                    break;
                }
                if (tube_prime[j] != 0) {
                    int t = tube_prime[j] / cell_prime[j] + (tube_prime[j] % cell_prime[j] ? 1 : 0);
                    if (t > need) need = t;
                }
            }
    
            if (valid && need < ans) ans = need;
        }
    
        if (ans == INT_MAX) puts("-1");
        else std :: printf("%d\n", ans);
        return 0;
    }
    

    评测记录

    评测记录