【每日一题】洛谷 P1069 (质因数分解)


想她一次就背十个单词,当我英语过六级后,我就去告诉她,我很在意她
一天一道数论题,当我可以秒杀数论题的时候,就开始做 DP	

划重点:
以后每天都会更新一道数论题,有兴趣的小伙伴可以关注一下,共同进步~~~

———————————————— 不正经的分界线 ————————————————
今日份快乐:洛谷 P1069 传送门
明日份快乐:洛谷 P1082 传送门

———————————————— 很正经的分界线 ————————————————

题目大意

博士要培养细菌平均装到 M 个试管中去做实验。M 很大,一般的数据类型装不下它。碰巧的是,M 正好可以分成 m1m2 的形式。
一共有 n 种细菌,对于每个第 i 种细菌,每天都可以分裂成 Si 个细菌。给出 m1 、m2 、n 和 对应的 Si。
问:最快什么时候可以去做实验

分析

就是找 Si 什么时候可以变成 M 的倍数
大佬们读完题就知道要质因数分解了,我这个菜鸡想了好久

质因数分解:任意的大于1 的整数都一定可以分解成质数幂乘积的形式
数学表达式为:n = 2x1 * 3x2 * 5x3 * 7x4……(x1,x2,x3…会根据 n 的不同而改变)

举个栗子:
对于样例【二】
2
24 1
30 12

我们先对 M 进行质因数分解得到
M = 2 3 * 3 1
接下来我们模拟一下细菌的增值过程,看表

--------第一天第二天第三天第四天
一号3090027000810000
二号12144172820736

好像看不出来啥,我们换个形式

--------第一天第二天第三天第四天
一号2 1* 31 * 512 2 * 3 2 * 5 22 3 * 3 3 * 5 32 4 * 3 4 * 5 4
二号22 * 3124 * 3226 * 3328 * 3 4

对比 M = 2 3 * 3 1
一号细菌在第三天的时候可以整除 M
二号细菌在第二天的时候可以整除 M
答案就是 2 了

我们应该可以看出来,对于一个细菌,如果经过增值可以被均分成 M 份,那么这个细菌对应的 Si 的质因子一定全部包含 M 全部的质因子

解题思路

step1:筛选出来所有的质数
step2:找 M 的质因子,同时遍历待选细菌,如果细菌不能被 M 的质因数整除这个细菌就不会增值成 M 的倍数
step3:遍历待选细菌,选出最佳答案。如果这时候没有待选细菌,就输出 -1

代码

#include <bits/stdc++.h>
using namespace std;

typedef struct Node{	
 int num;	// 质因数
 int sum;	// 次幂
}node;

int pr[5000];
bool flag[30005];
int num = 0;
void Init(){              // 筛选质数 
	for(int i = 2; i < 30000; i++){
		if(!flag[i]) pr[num++] = i;
		for(int j = 0; j < num; j++){
			if(pr[j] * i > 30005) break;
			flag[pr[j] * i] = true;
			if(i % pr[j] == 0) break;
		}
	}
}

int main(){

	ios::sync_with_stdio(false);
	
	Init();

	ll n;
 	cin >> n;
 	ll m1, m2;
	cin >> m1 >> m2;
 	queue<ll>v;           //存待选的细菌 
 	ll b;
 	for(int i = 1; i <= n; i++){
  	cin >> b;
  	v.push(b);
 	}

	vector<node>v1;      // 存 m1^m2 的质分解的结果 
 	for(int i = 0; m1 != 1; i++){
  		if(m1 % pr[i] == 0){        //如果 pr[i] 是 m1^m2 的质因子就存起来 
  			node a = {pr[i], 0};
   			while(m1 % pr[i] == 0){  // 算一下是多少次幂 
   				m1 /= pr[i];
    				a.sum++;
   			}
   			a.sum *= m2;             // 别忘了 m2 
   			v1.push_back(a);
   			int len = v.size();
   			for(int j = 1; j <= len; j++){    // 顺便判断待选细菌符合不符合 
   				int c = v.front();	//从队列中拿出来
    				v.pop();
    				if(c % pr[i] == 0) v.push(c);  //符合就再放回去
   			}
   		}
   	}
	
	if(v.empty()) cout << -1 << endl;        // 如果已经没有待选的答案,就输出 -1  
	else{
  		ll res = INF;
  		int len = v.size();
  		for(int i = 1; i <= len; i++){       // 寻找最佳答案 
   			int c = v.front();
   			ll temp = 0;
   			for(int j = 0; j < v1.size(); j++){   // 遍历 m1^m2 的质因子
    				ll sum = 0;
    				while(c % v1[j].num == 0){
     					sum++;
     					c /= v1[j].num;
    				}
    				temp = max(temp, (v1[j].sum + sum - 1) / sum);
   			}
   			res = min(temp, res);
   			v.pop();
   		}
  	cout << res << endl;
  	}
   return 0;
}

如果有解释不清楚的地方,欢迎留言

坚持的时候很狼狈,等你成功以后,丑的还是丑的 🤭
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值