题解:洛谷 P1069 [NOIP 2009 普及组] 细胞分裂
【题目来源】
洛谷:[P1069 NOIP 2009 普及组] 细胞分裂 - 洛谷
【题目描述】
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\) 个数 \(S_i\) 表示第 \(i\) 种细胞经过 \(1\) 秒钟可以分裂成同种细胞的个数。
【输出】
一个整数,表示从开始培养细胞到实验能够开始所经过的最少时间(单位为秒)。
如果无论 Hanks 博士选择哪种细胞都不能满足要求,则输出整数 \(−1\)。
【输入样例】
1
2 1
3
【输出样例】
-1
【算法标签】
《洛谷 P1069 细胞分裂》 #数学# #素数判断,质数,筛法# #NOIP普及组# #2009#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 10005, M = 30005; // 定义最大细胞数和最大质数范围
int n; // 细胞数量
int m_1, m_2; // 试管参数m1和m2
int s[N]; // 每个细胞的编号
int p[M], len; // 质数数组和质数个数
int B[M], T[M]; // B存储m1的质因数分解,T临时存储分解结果
int ans = -1; // 最终答案,初始为-1
// 判断是否为质数
bool isPrime(int x)
{
if (x == 1) return false;
for (int i = 2; i <= sqrt(x); i++)
if (x % i == 0) return false;
return true;
}
// 质因数分解函数
void D(int x)
{
memset(T, 0, sizeof(T));
for (int i = 1; i <= len; i++) // 遍历所有质数
{
while (x % p[i] == 0) // 能被当前质数整除
{
T[i]++; // 对应质数的指数加1
x /= p[i]; // 除掉这个质因数
}
}
return;
}
int main()
{
// 输入数据
cin >> n >> m_1 >> m_2;
for (int i = 1; i <= n; i++)
cin >> s[i];
// 特判:如果m1=1,直接输出0
if (m_1 == 1)
{
cout << 0 << endl;
return 0;
}
// 预处理:筛出30000以内的所有质数
for (int i = 2; i <= 30000; i++)
if (isPrime(i))
p[++len] = i;
// 对m1进行质因数分解
D(m_1);
// 备份m1^m2的质因数分解结果
for (int i = 1; i <= len; i++)
B[i] = T[i] * m_2;
// 处理每个细胞
for (int i = 1; i <= n; i++)
{
// 对当前细胞编号进行质因数分解
D(s[i]);
int cnt = -1;
// 检查是否满足条件
for (int j = 1; j <= len; j++)
{
if (B[j]) // 如果m1^m2有这个质因数
{
if (T[j] == 0) // 但细胞没有这个质因数
{
cnt = -1; // 不满足条件
break;
}
else
{
// 计算需要的倍数
int k = ceil(1.0 * B[j] / T[j]);
cnt = max(cnt, k);
}
}
}
// 更新答案
if (cnt != -1)
{
if (ans == -1)
ans = cnt;
else
ans = min(ans, cnt);
}
}
// 输出结果
cout << ans << endl;
return 0;
}
【运行结果】
1
2 1
3
-1
浙公网安备 33010602011771号