#P2768. 第1题-数字凸包区间
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 40
            Accepted: 17
            Difficulty: 2
            
          
          
          
                       所属公司 : 
                              米哈游
                                
            
                        
              时间 :2025年3月29日
                              
                      
          
 
- 
                        算法标签>模拟          
 
第1题-数字凸包区间
题解
题面描述
给定一个整数 n 和一个长度为 n 的数组 a1,a2,…,an。定义任意区间 [l,r] 的数字凸包区间为
[min{al,…,ar},max{al,…,ar}].对于每个前缀 [1,i](i=1,2,…,n),求该前缀构成的数字凸包区间中不属于该区间的最小非负整数。
例如:
- 当 i=1 时,区间为 [min{a1},max{a1}]=[a1,a1],如果 a1=0 则 0 不在该区间,答案为 0;
 - 当 i≥1 且 min{a1,…,ai}=0 时,则区间为 [0,M](其中 M=max{a1,…,ai}),区间内包含所有 0,1,…,M,所以答案为 M+1。
 
思路分析
对于每个 i,我们只需维护前缀的最小值 mi 和最大值 Mi。
- 若 mi>0,说明区间 [mi,Mi] 不包含 0,因此答案为 0。
 - 若 mi=0,则区间为 [0,Mi],因此答案为 Mi+1。
 
时间复杂度为 O(n),适用于 n≤2×105 的数据规模。
代码分析
在遍历数组时维护两个变量:
- min_val:前缀最小值
 - max_val:前缀最大值
 
对于每个位置 i:
- 更新 min_val=min(min_val,ai)
 - 更新 max_val=max(max_val,ai)
 - 如果 min_val>0,输出答案 0;否则输出答案 max_val+1。
 
C++
#include <iostream>
#include <algorithm>
using namespace std;
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    int a;
    // 初始化前缀最小值为一个较大的数,前缀最大值为0
    int min_val = 1e9 + 1, max_val = 0;
    for (int i = 1; i <= n; i++){
        cin >> a;
        // 更新前缀最小值和最大值
        min_val = min(min_val, a);
        max_val = max(max_val, a);
        // 如果前缀中最小值大于0,则答案为0;否则答案为 max_val+1
        if(min_val > 0)
            cout << 0 << " ";
        else
            cout << max_val + 1 << " ";
    }
    return 0;
}
Python
# 读取输入
n = int(input())
a_list = list(map(int, input().split()))
# 初始化前缀最小值为较大的数,前缀最大值为0
min_val = 10**9 + 1
max_val = 0
result = []
# 遍历数组更新前缀最值
for i in range(n):
    a = a_list[i]
    min_val = min(min_val, a)  # 更新前缀最小值
    max_val = max(max_val, a)  # 更新前缀最大值
    # 判断前缀最小值是否大于0
    if min_val > 0:
        result.append(0)
    else:
        result.append(max_val + 1)
        
# 输出结果,以空格分隔
print(" ".join(map(str, result)))
Java
import java.util.*;
import java.io.*;
 
public class Main {
    public static void main(String[] args) throws IOException {
        // 使用BufferedReader提高输入效率
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine().trim());
        String[] parts = br.readLine().trim().split("\\s+");
 
        // 初始化前缀最小值和前缀最大值
        int minVal = (int)1e9 + 1;
        int maxVal = 0;
        StringBuilder sb = new StringBuilder();
 
        // 遍历数组更新前缀最值
        for (int i = 0; i < n; i++) {
            int a = Integer.parseInt(parts[i]);
            // 更新前缀最小值
            minVal = Math.min(minVal, a);
            // 更新前缀最大值
            maxVal = Math.max(maxVal, a);
            // 如果前缀最小值大于0,则输出0;否则输出 maxVal+1
            if (minVal > 0) {
                sb.append("0 ");
            } else {
                sb.append((maxVal + 1) + " ");
            }
        }
 
        // 输出结果
        System.out.println(sb.toString().trim());
    }
}
        题目内容
米小游有n个整数{a1,a2,...,an},他定义区间[l,r]的“数字凸包区间”为 [min{al,...,ar},max{al,...,ar}]。
现在,对于每一个i=1,2,...,n,直接输出不属于[1,i]这个区间的“数字凸包区间”的最小非负整数。
输入描述
第一行输入两个整数n(1≦n≦2×105)代表整数数量询问次数。
第二行输入n个整数a1,a2,...,an(0≦ai≦109)代表元素
输出描述
在一行上输出n个整数,代表对于每一个i的答案。
样例1
输入
5
1 0 4 5 1
输出
0 2 5 6 6
说明
对于第一次询问,“数字凸包区间”为[1,1],不属于这个“数字凸包区间”的最小非负整数为0。
对于第二次询问,“数字凸包区间”为[0,1],不属于这个“数字凸包区间”的最小非负整数为2。