原题截图
题意分析
分析题干可以发现,选择两个元素和以及的一个因子,进行,的操作,实际上就相当于在的素因子的可重集合中删去一个元素,并将加入的素因子的可重集合中,所以可以将题意转化为以下的等价版本。
有一个数组以及个可重集合,可以进行的操作为:选择两个可重集合与,从中删去一个元素,并将加入中(其中对于,可重集合中存放的是的所有素因子)。问能否通过若干次操作,使每个可重集合中的元素的种类数至多为,若能,返回"Yes",否则返回"No"。
*种类数的解释:例如,可重集合的元素种类数为,因为所有的视为同一种元素,所有的也视为同一种元素。
解题思路
在将题意转化为上述等价版本后,题目的难点仅剩素因子的分解,因为通过素因子的分解得出数组中每个数的素因子后,也就得出了可重集合中的元素。容易得出,题目返回"Yes"的充要条件即为:所有可重集合中的元素的种类数,即数组中所有数的素因子的种类数。
对于素因子(后面统一称为“质因数”)的分解,由于豆包MarsCode AI刷题平台的题目未给出数据范围,因此先假设数据范围足够小,直接用试除法分解质因数。具体过程为:设要分解质因数为ai,设ceil(sqrt(ai))为sai,从2开始按步长1向后遍历,设遍历到的元素为j,并在不满足j<=ai && j<=sai时结束遍历,如果ai%j == 0则ai /= j;,并向记录所有数的素因子的种类数的集合st中放入j,如果遍历完成后,仍然有ai != 1,则向集合st中放入ai。更加准确的过程描述请见代码实现部分。
如果实际的数据范围较大,可以先用埃氏筛、欧拉筛等质数筛在或接近的时间复杂度下筛选出区间内的质数,然后用筛出来的质数去分解质因数,可以避免遍历到不是质数的数,从而降低一定的时间复杂度。
代码实现
#include <bits/stdc++.h>
using namespace std;
string solution(int n,vector<int>& a)
{
set<int> st;
for (auto&& ai : a)
{
int sai = ceil(sqrt(ai));
for(int j=2;j<=ai && j<=sai;j++)
{
while(ai%j == 0)
{
ai /= j;
st.insert(j);
}
}
if(ai != 1) st.insert(ai);
}
return st.size()<=a.size() ? "Yes" : "No";
}
总结
本题使用简单的试除法分解质因数,设数组的长度为,数组中元素的最大值为,则时间复杂度为,空间复杂度为;如果的值较大,可以使用质数筛来降低时间复杂度的常数值(当来到大约至的数量级时,大约可将复杂度常数值降到原来的到,即这一范围内质数与所有数的个数之比)。如果你有复杂度更优的解法,欢迎在下方评论。