[编程题]mex
  • 热度指数:486 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}给你一个由 n自然数(非负整数)组成的数组 \{a_1,a_2,\dots,a_n\},我们定义一轮操作:
\hspace{23pt}\bullet\,计算出当前数组的 \operatorname{mex},随后,使得所有的 a_i := \max\{0,a_i - \operatorname{mex}\}。换句话说,对于任意的 1\leqq i\leqq n,使得 a_i\gets \max \{0,a_i - \operatorname{mex}\}
\hspace{15pt}小牛想知道你至少需要执行多少轮(也可以不执行)操作,才能使得数组 a 中的每个数都相同?如果无法使得数组 a 中的每个数都相同,则直接输出 -1

\hspace{15pt}整数数组的 \operatorname{mex} 定义为没有出现在数组中的最小非负整数。例如 \operatorname{mex} \{1,2,3 \} =0\operatorname{mex} \{0,2,5\} =1

输入描述:
\hspace{15pt}第一行输入一个整数 n\left(1\leq n\leq 10^5\right) 代表数组中的元素数量。 
\hspace{15pt}第二行输入 n 个整数 a_1,a_2,\dots,a_n\left(0\leq a_i\leq 10^{18}\right) 代表数组中的元素。


输出描述:
\hspace{15pt}如果无法使得数组 a 中的每个数都相同,则直接输出 -1;否则,输出一个整数,代表至少需要执行的轮数。
示例1

输入

6
0 1 2 3 4 5

输出

1

说明

\hspace{15pt}在这个样例中,第一轮数组的 \operatorname{mex}6,所以:
\hspace{23pt}\bullet\,对于第一个元素 0,使用 \max\{0,0-6\}=0 替换;
\hspace{23pt}\bullet\,对于第二个元素 1,使用 \max\{0,1-6\}=0 替换;
\hspace{23pt}\bullet\,对于第三个元素 2,使用 \max\{0,2-6\}=0 替换;
\hspace{23pt}\bullet\,对于第四个元素 3,使用 \max\{0,3-6\}=0 替换;
\hspace{23pt}\bullet\,对于第五个元素 4,使用 \max\{0,4-6\}=0 替换;
\hspace{23pt}\bullet\,对于第六个元素 5,使用 \max\{0,5-6\}=0 替换。
\hspace{15pt}得到数组 \{0,0,0,0,0,0\},满足题干条件。所以,至少需要执行 1 轮操作。
示例2

输入

5
3 1 2 4 5

输出

-1

说明

\hspace{15pt}在这个样例中,由于第一轮数组的 \operatorname{mex}0,所以无论执行多少次操作,数组都不会改变,所以无法使所有数变为相同值。
示例3

输入

6
0 1 3 4 7 9

输出

5

说明

\hspace{15pt}在这个样例中:
\hspace{23pt}\bullet\,第一轮操作:\operatorname{mex}=2,操作完后数组变为 \{0,0,1,2,5,7\}
\hspace{23pt}\bullet\,第二轮操作:\operatorname{mex}=3,操作完后数组变为 \{0,0,0,0,2,4\}
\hspace{23pt}\bullet\,第三轮操作:\operatorname{mex}=1,操作完后数组变为 \{0,0,0,0,1,3\}
\hspace{23pt}\bullet\,第四轮操作:\operatorname{mex}=2,操作完后数组变为 \{0,0,0,0,0,1\}
\hspace{23pt}\bullet\,第五轮操作:\operatorname{mex}=2,操作完后数组变为 \{0,0,0,0,0,0\}
\hspace{15pt}综上所述,至少需要执行 5 轮操作。
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        long[] a = new long[n]; 
        
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextLong();
        }
        
        System.out.println(minOperations(a, n));
        scanner.close();
    }
    
    private static Long minOperations(long[] a, int n) {
        // 情况1:如果数组中所有元素已经相同,返回0
        if (allElementsSame(a, n)) {
            return 0L;
        }
        
        // 检查数组中是否包含0
        boolean hasZero = false;
        for (long num : a) {
            if (num == 0) {
                hasZero = true;
                break;
            }
        }
        
        // 情况2:如果数组元素不相同且不包含0,则不可能完成,返回-1
        if (!hasZero) {
            return -1L;
        }
        
        // 收集所有正整数并去重
        Set<Long> positiveNumbers = new HashSet<>();
        for (long num : a) {
            if (num > 0) {
                positiveNumbers.add(num);
            }
        }
        
        // 将去重后的正整数转换为列表并排序
        List<Long> positives = new ArrayList<>(positiveNumbers);
        Collections.sort(positives);
        
        // 正整数的个数使用int类型
        int m = positiveNumbers.size();
        // 最大的正整数
        long maxP = positives.get(m - 1);
        
        // 应用公式计算结果:maxP - (m - 1)
        return maxP - (m - 1);
    }
    
    // 检查数组是否所有元素都相同
    private static boolean allElementsSame(long[] a, int n) {
        if (n <= 1) {
            return true;  // 空数组或只有1个元素,自然所有元素相同
        }
        
        long first = a[0];  // 以第一个元素为基准
        for (int i = 1; i < n; i++) { 
            if (a[i] != first) {  // 只要有一个元素与基准不同,就返回false
                return false;
            }
        }
        return true;  // 所有元素都与基准相同,返回true
    }
}
    

发表于 2025-09-21 15:04:26 回复(0)