[luogu p1069] 细胞分裂

传送门

细胞分裂

题目描述

\(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;
}

评测记录

评测记录

posted @ 2020-10-03 14:49  dbxxx  阅读(266)  评论(0编辑  收藏  举报