[NOIP2009]细胞分裂

题目描述

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

\(Hanks\) 博士手里现在有 NN种细胞,编号从 \(1-N\),一个第 \(i\)种细胞经过 \(1\) 秒钟可以分裂为\(S_i\)个同种细胞(\(S_i\) 为正整数)。现在他需要选取某种细胞的一个放进培养皿,让其自由分裂,进行培养。一段时间以后,再把培养皿中的所有细胞平均分入\(M\)个试管,形成\(M\)份样本,用于实验。\(Hanks\) 博士的试管数MM很大,普通的计算机的基本数据类型无法存储这样大的\(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

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/(24)=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\)

sol

题目意思很简单,\({m1^{m2}|{s_i}^k}\)给你\(s_i,m1,m2\),让你找出最小的k。
也就是\({s_i}^k\) \(mod\) \(m1^{m2} =0\)。不会的题先写暴力,暴力应该非常好写吧。枚举时间k,如果能整除就退出循环,快速幂优化一下,但是还是会超时,这是肯定的。
那么正解怎么做呢。我们看到整除,是不是可以想到质因数分解(其实也可以用gcd写)。

如果\(s_i\)的所有质因子没有完全包含\(m1^{m2}\)的质因子,那么\(s_i\)再怎样乘方都无法整除\(m1^{m2}\),想想为什么,举个栗子。
假如\(s_i\)\(24\)\(24=2^3*3^1\)\(m1^{m2}\)\(30\)\(30=2^1*3^1*5^1\),因为\(s_i\)的n次方,也就是\({24}^n=2^{3*n}*3^{1*n}\),无论n有多大,都不可能出现\(5\)这个质因子。所以无法整除。

所以如果\(s_i\)的所有质因子完全包含\(m1^{m2}\)的质因子,那么一定能够整除,那么这个k怎么计算呢。用\(m1^{m2}\)\(s_i\)的相同的质因子(相同的底数),k为\(m1^{m2}\)\(s_i\)的指数相除取最大值。

想想为什么,我们刚刚说过,按照样例来说\(s_i\)\(30\)\(m1^{m2}\)为24,因为我们刚刚说过,\(s_i\)的n次方,可以表示为\({30}^n=2^{1*n}*3^{1*n}*5^{1*n}\)。因为\(24=2^3*3^1\),那么反过来,这个\(k=3\),这个值一定就可以整除\(m1_{m2}\),所以k就等于\(m1^{m2}\)\(s_i\)的每个相同质因子相除再取上最大值。

接着我们看到数据范围\(1 ≤m_1 ≤ 30000,1 ≤m_2 ≤ 10000\)\(m=m1^{m2}\)\(m\)最大有\(30000^{10000}\),开什么类型都会爆,所以该怎么质因数分解呢。我们可以先将\(m1\)分解质因数,然后指数乘上\(m2\),想想为什么。
因为\((a^b)^n=a^{b*n}\)

\[\begin{aligned} m1&=a_1^{p_1}*a_2^{p_2}*a_3^{p_3}*...*a_n^{p_n}\\ m1^{m2}&=(a_1^{p_1})^{m2}*(a_2^{p_2})^{m2}*(a_3^{p_3})^{m2}*...*(a_n^{p_n})^{m2}\\ m&=a_1^{p_1*m2}*a_2^{p_2*m2}*a_3^{p_3*m2}*...*a_n^{p_n*m2}\\ \end{aligned} \]

所以找出最小的k,这个问题就迎刃而解了。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool prime(int x){//线性筛质数 
    if(x==1)return 0;
    if(x==2||x==3)return 1;
    if(x%6!=1&&x%6!=5)return 0;
    int temp=sqrt(x);for(int i=5;i<=temp;i+=6)if(x%i==0||x%(i+2)==0)return 0;
    return 1;
}
inline int work(int x,int y){//判断是否整除,如整除输出商,否则输出商+1 
	if(x%y==0)return x/y;
	else return x/y+1;
}
const int maxn=1e5+10;
int n;
int m1,m2;
int s[maxn];
int sum_m[maxn],sum_cell[maxn];//下标为第i个质数,sum_m为m分解质因数后的指数,sum_cell为s[i]分解质因数后的质数 
int pr[maxn];
int tot=1,sum_pr;
bool opt,flag;
int ans,minn=1<<30;
int main(){
	cin>>n>>m1>>m2;
	if(m1==1){puts("0");return 0;}
	for(int i=1;i<=n;i++)cin>>s[i];
	for(int i=2;i<=100000;i++)if(prime(i))++sum_pr,pr[sum_pr]=i;//统计质数个数,把质数搞出来 
	while(m1!=1){//把m分解质因数 
		if(m1%pr[tot]==0){
			while(m1%pr[tot]==0)
			  sum_m[tot]++,m1/=pr[tot];
		}
		sum_m[tot]*=m2;//小技巧,前文提到过 
		++tot;
	}
	for(int i=1;i<=n;i++){
		bool flag=false;tot=1,ans=-1;
		memset(sum_cell,false,sizeof(sum_cell));//注意清空数组 
		while(s[i]!=1){//为s[i]分解质因数 
			if(s[i]%pr[tot]==0){
				while(s[i]%pr[tot]==0)
				  sum_cell[tot]++,s[i]/=pr[tot];
			}
			++tot;
		}
		for(int j=1;j<=sum_pr;j++){
			if(sum_m[j]&&!sum_cell[j])flag=true;//如果没有完全包含,这个s[i]的答案就为-1 
			if(sum_m[j]&&sum_cell[j])ans=max(ans,work(sum_m[j],sum_cell[j]));//如果完全包含,计算即可 
		}
		if(!flag){opt=true;minn=min(minn,ans);}//取最大值 
	}
	if(opt)printf("%d",minn);//只要有能整除的就输出 
	else puts("-1");//如果所有的细胞都不行,就无解输出-1 
	return 0;
}
posted @ 2020-08-14 10:45  qzwer  阅读(413)  评论(2编辑  收藏  举报