P1069 [NOIP2009 普及组] 细胞分裂

传送门

题意:

给你m1,m2,现在有 M = m 1 m 2 M = m1^{m2} M=m1m2个试管,n种细胞,每种细胞经过1s可以分裂成 a i a^i ai个细胞,问你可以将细胞平均分配到M个试管的最短时间。

思路:

先得出m1的质因数集合s1以及这些m1中这些质因数的个数,可以想到:如果i细胞可以在有限的时间内得到合适的数量使其可以分配到M个试管中去,那么i细胞每次分裂的个数ai,它的质因数集合设为s2,则s1一定包含于s2。
于是,s2集合里的质因数每秒加1,而s1里的每种质因数的个数应该还需要乘上m2,最后我们只需要计算出s2里的和s1同种的质因数数量超过s1最多需要多少秒,最后比较所有符合条件的ai即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll prims[100000];
ll vis[1000010];
ll cnt = 0;

void prim()
{
    
    
	 for(ll i=2;i<=10000;i++)
	 {
    
    
	 	if(!vis[i])
	 	{
    
    
	 		prims[++cnt]=i;
		 }
		 for(ll j=1;j<=cnt;j++)
		 {
    
    
		 	if(prims[j]*i<=10000)
		 	vis[prims[j]*i]=1;
		 	else
		 	break;
		 	if(i%prims[j]==0)
		 	break;
		 }
	 }
}
ll same[10000];
ll m_prim[10000];
ll ans[100000];
ll m_sum[10000];
ll a[10010];
ll now_prim[10000];
ll num_prim[10000];
ll sum_prim[10000];

int main()
{
    
    
	ll n;
	cin>>n;
	ll m1,m2;
	cin>>m1>>m2;
	prim();
	for(ll i = 1; i <= n; i++) cin>>a[i];
	ll num = 0;
	for(ll i = 1; i <= cnt; i++)
	{
    
    
		if(m1%prims[i] == 0)m_prim[++num] = prims[i];
		while(m1%prims[i] == 0)same[prims[i]]++,m1 /= prims[i];
		if(prims[i] > m1)break;
	}
	ll ans_num = 0;
	for(ll i = 1; i <= n; i++)
	{
    
    
		ll flag = 0;
		for(ll j = 1; j <= cnt; j++)
		{
    
    
			if(flag == num)break;
			if(a[i]%prims[j] == 0)
			{
    
    
				if(m_prim[++flag] < prims[j])
				{
    
    
					flag = -1;
					break;
				}
				else if(m_prim[flag] > prims[j])flag--;
			}
		}
		if(flag == num)ans[++ans_num] = a[i];
	}
	if(ans_num == 0)
	{
    
    
		cout<<-1<<endl;
		return 0;
	}
	for(ll i = 1; i <= num; i++)
	{
    
    
		sum_prim[i] = same[m_prim[i]]*m2;
	}
	ll res = 0x7f7f7f7f;
	for(ll i = 1; i <= ans_num; i++)
	{
    
    
		ll now = ans[i];
		ll flag = 0;
		for(ll j = 1; j <= num; j++)
		{
    
    
			if(now%m_prim[j] == 0)
			{
    
    
				now_prim[++flag] = m_prim[j];
				while(now%m_prim[j] == 0)
				{
    
    
					now /= m_prim[j];
					num_prim[m_prim[j]]++;
				}
				if(m_prim[j] > now || flag == num)break;
			}
		}
		ll c = 0;
		for(ll j = 1; j <= num; j++)
		c = max(c, (ll)ceil(sum_prim[j]*1.0/num_prim[now_prim[j]]));
		res = min(c, res);
		memset(num_prim,0,sizeof(num_prim));
	}
	cout<<res<<endl;
}

Guess you like

Origin blog.csdn.net/p15008340649/article/details/120485712