小M的数组变换 | 豆包MarsCode AI刷题

221 阅读4分钟

问题描述

小M拿到一个数组,她可以进行多次操作,每次操作可以选择两个元素 aia_iaja_j,并选择 aia_i 的一个因子 xx,然后将 aia_i 变为 ai/xa_i / x,并将 aja_j 变为 aj×xa_j \times x。她的目标是通过有限次操作,使得数组中的每个元素最多只包含一种素因子。

素因子的定义是:若 xx 能被素数 pp 整除,那么 ppxx 的一个素因子。例如,1212 的素因子有 2233

你的任务是判断是否有可能通过有限次操作,使数组中的每个元素最多只包含一种素因子。如果可以,输出 "Yes",否则输出 "No"


测试样例

样例1:

输入:n = 4 ,a = [1, 2, 3, 4] 输出:'Yes'

样例2:

输入:n = 2 ,a = [10, 12] 输出:'No'

样例3:

输入:n = 3 ,a = [6, 9, 15] 输出:'Yes'

思路

1、观察题目和用例:

(1)每次操作可以选择两个元素 aia_iaja_j,并选择 aia_i 的一个因子 xx,然后将 aia_i 变为 ai/xa_i / x,并将 aja_j 变为 aj×xa_j \times x

假设我们存在两个数:10 和 36

依题,我们需要计算这两个数的素因子(为素数的因子),10为2、5,36为2、2、3、3

tips:题目要求最终答案每个元素只包含一个素因子,因此我们尽量将所有因子分解为素因子

对于每次操作,将 aia_i 变为 ai/xa_i / x,并将 aja_j 变为 aj×xa_j \times x我们可以将每个元素视作素因子的集合,每次操作的本质就是将一个集合中的元素移动到另一个集合中

如10(2,5)和36(2,2,3,3),可以变为20(2,2,5)和18(2,3,3)

(2)使数组中的每个元素最多只包含一种素因子

Q:什么情况下一个元素只存在一个素因子?

A:

情况一:这个元素本身就是素数(如7)

情况二:这个元素是单一素因子的乘积(如22=42*2 = 433=93*3 = 9

综上,为了检查是否可以让每个元素都包含一个素因子,我们应当尽量将相同的素因子移动到同一个元素(集合)中,可以转化为所有元素的素因子的个数不超过元素的个数

如样例3:a=[6915]a = [6,9,15], 素因子为[[2,3],[3,3],[3,5]][[2, 3], [3, 3], [3, 5]],三个元素,三种素因子,每个素因子最终都可以归到一个集合中,因此结果是"Yes"

如样例2:a=[10,12]a = [10, 12], 素因子为[[2,5],[2,3]][[2,5], [2,3]],两个元素,三种素因子,每个素因子无法归到一个集合中,因此结果是"No"

(3)如何快速计算素因子

可以使用埃氏筛或欧拉筛(线性筛)

本题解使用埃式筛,由于题目数据较弱,只需要筛出20往前的素数即可

埃氏筛大致逻辑如下

1、 创建一个从2到给定数字n的列表,初始化为全为“素数”(未被筛掉)。

2、 从列表中找到第一个未被标记的数字,这一定是一个素数。

3、 标记这个数字的所有倍数为“非素数”。

4、 重复步骤2和步骤3,直到处理的数字超过范围。

5、 剩下未被标记的数字即为素数。

// 保存素数
static List<Integer> p = new ArrayList<>();
static {
    // 判断一个i是否是素数,本题范围为20以内即可AC
    boolean[] temp = new boolean[20];
    // 初始化
    Arrays.fill(temp, true);
    temp[0] = false;
    temp[1] = false;
    for (int i = 2; i < temp.length; i++) {
        for(int j = 2;i*j<temp.length;j++){
            temp[i*j] = false;
        }
    }
    for (int i = 0; i < temp.length; i++) {
        // 是素数
        if (temp[i]) {
            p.add(i);
        }
    }
}

2、大致逻辑

  • 预处理素数
  • 遍历每个元素,统计每个元素中出现的素因数
  • 计算出现过的素因数个数是否<=元素个数

代码

static List<Integer> p = new ArrayList<>();

static {
    boolean[] pp = new boolean[10000];
    Arrays.fill(pp, true);
    pp[0] = false;
    pp[1] = false;
    for (int i = 2; i < pp.length; i++) {
        for (int j = 2; i * j < pp.length; j++) {
            pp[i * j] = false;
        }
    }
    for (int i = 0; i < pp.length; i++) {
        if (pp[i]) {
            p.add(i);
        }
    }
}

public static String solution(int n, int[] a) {
    // 统计素因子个数
    Set<Integer> set = new HashSet<>();
    for (int i = 0; i < a.length; i++) {
        for (int j = 0; p.get(j) <= a[i]; j++) {
            // 是因子
            if (a[i] % p.get(j) == 0) {
                set.add(p.get(j));
            }
        }
    }
    return set.size() <= a.length ? "Yes" : "No";
}

public static void main(String[] args) {
    System.out.println(solution(4, new int[]{1, 2, 3, 4}).equals("Yes"));
    System.out.println(solution(2, new int[]{10, 12}).equals("No"));
    System.out.println(solution(3, new int[]{6, 9, 15}).equals("Yes"));
}