细胞分裂 \operatorname{细胞分裂} 细胞分裂
题目链接: luogu P1069 \operatorname{luogu\ P1069} luogu P1069
题目
Hanks 博士是 BT ( Bio-Tech ,生物技术) 领域的知名专家。现在,他正在为一个细胞实验做准备工作:培养细胞样本。
Hanks 博士手里现在有
N
N
N 种细胞,编号从
1
−
N
1-N
1−N ,一个第
i
i
i 种细胞经过
1
1
1 秒钟可以分裂为
S
i
S_i
Si 个同种细胞(
S
i
S_i
Si 为正整数)。现在他需要选取某种细胞的一个放进培养皿,让其自由分裂,进行培养。一段时间以后,再把培养皿中的所有细胞平均分入
M
M
M 个试管,形成
M
M
M 份样本,用于实验。
H
a
n
k
s
Hanks
Hanks 博士的试管数
M
M
M 很大,普通的计算机的基本数据类型无法存储这样大的
M
M
M 值,但万幸的是,
M
M
M 总可以表示为
m
1
m_1
m1 的
m
2
m_2
m2 次方,即
M
=
m
1
m
2
M = m_1^{m_2}
M=m1m2 ,其中
m
1
,
m
2
m_1,m_2
m1,m2 均为基本数据类型可以存储的正整数。
注意,整个实验过程中不允许分割单个细胞,比如某个时刻若培养皿中有 4 4 4 个细胞,
Hanks 博士可以把它们分入 2 2 2 个试管,每试管内 2 2 2 个,然后开始实验。但如果培养皿中有 5 5 5 个细胞,博士就无法将它们均分入 2 2 2 个试管。此时,博士就只能等待一段时间,让细胞们继续分裂,使得其个数可以均分,或是干脆改换另一种细胞培养。
为了能让实验尽早开始, Hanks 博士在选定一种细胞开始培养后,总是在得到的细胞“刚好可以平均分入 M M M 个试管”时停止细胞培养并开始实验。现在博士希望知道,选择哪种细胞培养,可以使得实验的开始时间最早。
输入
第一行,有一个正整数 N N N ,代表细胞种数。
第二行,有两个正整数 m 1 , m 2 m_1,m_2 m1,m2 ,以一个空格隔开,即表示试管的总数 M = m 1 m 2 M = m_1^{m_2} M=m1m2 .
第三行有 N N N 个正整数,第 i i i 个数 S i S_i Si 表示第 i i i 种细胞经过 1 1 1 秒钟可以分裂成同种细胞的个数。
输出
一个整数,表示从开始培养细胞到实验能够开始所经过的最少时间(单位为秒)。
如果无论 Hanks 博士选择哪种细胞都不能满足要求,则输出整数 − 1 -1 −1 。
样例输入1
1
2 1
3
样例输出1
-1
样例1解释
经过 1 1 1 秒钟,细胞分裂成 3 3 3 个,经过 2 2 2 秒钟,细胞分裂成 9 9 9 个, … … … ,可以看出无论怎么分裂,细胞的个数都是奇数,因此永远不能分入 2 2 2 个试管。
样例输入2
2
24 1
30 12
样例输出2
2
样例2解释
第 1 1 1 种细胞最早在 3 3 3 秒后才能均分入 24 24 24 个试管,而第 2 2 2 种最早在 2 2 2 秒后就可以均分(每试管 144 / ( 241 ) = 6 144/(241)=6 144/(241)=6 个)。故实验最早可以在 2 2 2 秒后开始。
数据范围
对于 50 % 50\% 50% 的数据,有 m 1 m 2 ≤ 30000 m_1^{m_2} ≤ 30000 m1m2≤30000 。
对于所有的数据,有 1 ≤ N ≤ 10000 , 1 ≤ m 1 ≤ 30000 , 1 ≤ m 2 ≤ 10000 , 1 ≤ S i ≤ 2 , 000 , 000 , 000 1 ≤N≤ 10000,1 ≤m_1 ≤ 30000,1 ≤m_2 ≤ 10000,1 ≤ S_i ≤ 2,000,000,000 1≤N≤10000,1≤m1≤30000,1≤m2≤10000,1≤Si≤2,000,000,000 。
思路
这道题也是一道数论。
我们可以分别把试管数量和一个细胞的分裂速度给质因数分解,那我其实可以发现,对于某一个细胞,我们让这个细胞分裂速度分解出来的质因数包含了所有试管数量分解出的质因数,那这个细胞就符合。
啥?怎么看符合的细胞要分裂几次?
就让细胞的每一个质因数乘一个尽可能小数,让每个质因数都大于试管数量那边的。
(感觉说不清楚,看代码吧)
代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n, m1, m2, su_num, susu[30001], now, x, mfenjie[30001], xfenjie[30001], ans, answer = 2147483647;
bool yessu[30001], yes, can;
void get_susu() {//素数筛选法
yessu[0] = yessu[0] = 1;
for (int i = 2; i <= 30000; i++)
if (!yessu[i]) {
su_num++;
susu[su_num] = i;
for (int j = i + i; j <= 30000; j += i)
yessu[j] = 1;
}
}
int main() {
get_susu();
scanf("%d", &n);//读入
scanf("%d %d", &m1, &m2);
now = 1;
while (m1 > 1) {//质因数分解
while (m1 % susu[now] == 0) {
mfenjie[now] += m2;
m1 /= susu[now];
}
now++;
}
for (int i = 1; i <= n; i++) {
ans = 0;
memset(xfenjie, 0, sizeof(xfenjie));//初始化
scanf("%d", &x);
now = 1;
while (now <= su_num && x > 1) {//质因数分解
while (x % susu[now] == 0) {
xfenjie[now]++;
x /= susu[now];
}
now++;
}
yes = 1;
for (int j = 1; j <= su_num; j++) {
if (mfenjie[j] && !xfenjie[j]) {//没得配对,直接不行
yes = 0;
break;
}
if (mfenjie[j] && xfenjie[j]) {
if (mfenjie[j] % xfenjie[j] == 0) ans = max(ans, mfenjie[j] / xfenjie[j]);
else ans = max(ans, mfenjie[j] / xfenjie[j] + 1);
}
}
if (yes) {
can = 1;
answer = min(answer, ans);
}
}
if (!can) {//不行
printf("-1");
return 0;
}
printf("%d", answer);//输出
return 0;
}