【每日一題】洛谷 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
接下來我們模擬一下細菌的增值過程,看錶

-------- 第一天 第二天 第三天 第四天
一號 30 900 27000 810000
二號 12 144 1728 20736

好像看不出來啥,我們換個形式

-------- 第一天 第二天 第三天 第四天
一號 2 1* 31 * 51 2 2 * 3 2 * 5 2 2 3 * 3 3 * 5 3 2 4 * 3 4 * 5 4
二號 22 * 31 24 * 32 26 * 33 28 * 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;
}

如果有解釋不清楚的地方,歡迎留言

堅持的時候很狼狽,等你成功以後,醜的還是醜的 🤭
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章