华为OD机试双机位C卷 - 结对编程 (C++ & Python & JAVA & JS & GO)

结对编程

2025华为OD机试双机位C卷 - 华为OD上机考试双机位C卷 200分题型

华为OD机试双机位C卷真题目录点击查看: 华为OD机试双机位C卷真题题库目录|机考题库 + 算法考点详解

题目描述

某部门计划通过结队编程来进行项目开发,已知该部门有 N 名员工,每个员工有独一无二的职级,每三个员工形成一个小组进行结队编程,结队分组规则如下:

从部门中选出序号分别为 i、j、k 的3名员工,他们的职级分别为 level[i],level[j],level[k],结队小组满足 level[i] < level[j] < level[k] 或者 level[i] > level[j] > level[k],其中 0 ≤ i < j < k < n。

请你按上述条件计算可能组合的小组数量。同一员工可以参加多个小组。

输入描述

第一行输入:员工总数 n

第二行输入:按序号依次排列的员工的职级 level,中间用空格隔开

备注

  • 1 <= n <= 6000

  • 1 <= level[i] <= 10^5

输出描述

可能结队的小组数量

用例1

输入

none 复制代码
4
1 2 3 4

输出

none 复制代码
4

说明

可能结队成的组合(1,2,3)、(1,2,4)、(1,3,4)、(2,3,4)

用例2

输入

none 复制代码
3
5 4 7

输出

none 复制代码
0

题解

思路:逻辑分析 + 树状数组

  1. 这道题可以枚举中间j, 当枚举到nums[j], 它可以组成为左侧小于它的数量 * 右侧大于它的数量 + 左侧大于的数量 * 右侧小于它的数量分别对应level[i] < level[j] < level[k]的情况和level[i] > level[j] > level[k]的情况相加。
  2. 所以根据1的分析得来,只需要累加所有位置作为中间节点合法组合情况就能得到结果。那现在问题就转换为如何统计左侧小于它的数量, 右侧大于它的数量,左侧大于的数量,右侧小于它的数量, 然后由于这道题n <= 6000如果直接使用暴力统计很可能超时,接下来为了快速统计引入树状数组前缀和方式进行优化,达到快速得到上面所需要的四种数量。如果不了解树状数组,可以搜索去学习一下
  3. 开始定义trie1[max(nums) + 1], trie2[max(nums) + 1], 其中trie1[i], trie2[i]树状数组查询可以简单理解为记录小于等于i的数量。其中max(nums)表示最高职级大小
  4. 对于统计左侧比nums[j]大/小的数量比较好做,只需要在枚举 j 的过程中,将 nums[j]添加到树状数组 tri1 即可。具体值为
    • 左侧小于nums[j]的数量: tri1[nums[j] - 1]
    • 左侧大于nums[j]的数量: tri1[max(nums)] - trie1[nums[j]], 前缀和思想。
  5. 那么对于需要统计右侧比nums[j]小/大的数量,凭tri1无法做到,所以引入trie2树状数组,初始先将所有nums加入到trie2中,然后在在枚举 j 的过程中,将 nums[j]移除到树状数组 tri2 即可(其实就相当于把整个数组分为两部分,全部 - 左边 = 右边),然后就非常好统计,具体值为
    • 右侧小于nums[j]的数量为:tri2[nums[j] - 1]
    • 右侧大于nums[j]的数量为:tri2[max(nums[j])] - tri2[num[j]]
  6. 按照上面具体逻辑处理就能得到最终结果,然后输出即可。

c++

c++ 复制代码
#include <algorithm>
#include <cmath>
#include <iostream>
#include <map>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>

using namespace std;

const int N = 1e5 + 10;

// 树状数组 更新值
// 参数:tree 数组,index 更新的位置,delta 增加的值
void update(vector<int> &tree, int index, int delta) {
  int n = (int)tree.size() - 1;
  while (index <= n) {
    tree[index] += delta;      // 更新当前位置的值
    index += index & (-index); // 跳到所有包含这个位置的父区间
  }
}

// 树状数组 查询区间和
// 参数:tree 数组,index 查询的前缀位置
// 返回值:从1到index的区间和
int query(const vector<int> &tree, int index) {
  int res = 0;
  while (index > 0) {
    res += tree[index];        // 累加当前节点值
    index -= index & (-index); // 跳到上一个区间的父区间
  }
  return res;
}

int main() {
    int n;
    cin >> n;

    vector<int> nums(n);
    int maxv = 0;
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
        maxv = max(maxv, nums[i]);
    }
    
    // 树状数组
    vector<int> tri1(maxv + 1), tri2(maxv + 1);

    // tri2 先放所有元素
    for (int x : nums) {
        update(tri2, x, 1);
    }

    long long ans = 0;
    // 枚举中间值j
    for (int i = 0; i < n; i++) {
        int num = nums[i];

        // 当前元素从右侧移除
        update(tri2, num, -1);

        long long leftLess = query(tri1, num - 1);
        long long leftMore = query(tri1, maxv) - query(tri1, num);
        long long rightLess = query(tri2, num - 1);
        long long rightMore = query(tri2, maxv) - query(tri2, num);

        ans += leftLess * rightMore;
        ans += leftMore * rightLess;

        // 当前元素加入左侧
        update(tri1, num, 1);
    }

    cout << ans << endl;
    return 0;
}

JAVA

JAVA 复制代码
import java.util.*;

public class Main {
    // 树状数组更新
    static void update(int[] tree, int index, int delta) {
        int n = tree.length - 1;
        while (index <= n) {
            tree[index] += delta; // 更新当前位置
            index += index & -index; // 跳到父区间
        }
    }

    // 树状数组查询前缀和
    static int query(int[] tree, int index) {
        int res = 0;
        while (index > 0) {
            res += tree[index];
            index -= index & -index;
        }
        return res;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] nums = new int[n];
        int maxv = 0;
        for (int i = 0; i < n; i++) {
            nums[i] = sc.nextInt();
            maxv = Math.max(maxv, nums[i]);
        }

        int[] tri1 = new int[maxv + 1];
        int[] tri2 = new int[maxv + 1];

        // tri2 初始放所有元素
        for (int x : nums) {
            update(tri2, x, 1);
        }

        long ans = 0;
        for (int num : nums) {
            // 当前元素从右侧移除
            update(tri2, num, -1);

            long leftLess = query(tri1, num - 1);
            long leftMore = query(tri1, maxv) - query(tri1, num);
            long rightLess = query(tri2, num - 1);
            long rightMore = query(tri2, maxv) - query(tri2, num);

            ans += leftLess * rightMore + leftMore * rightLess;

            // 当前元素加入左侧
            update(tri1, num, 1);
        }

        System.out.println(ans);
    }
}

Python

python 复制代码
# 树状数组更新
def update(tree, index, delta):
    n = len(tree) - 1
    while index <= n:
        tree[index] += delta
        index += index & -index

# 树状数组查询前缀和
def query(tree, index):
    res = 0
    while index > 0:
        res += tree[index]
        index -= index & -index
    return res

n = int(input())
nums = list(map(int, input().split()))
maxv = max(nums)

tri1 = [0] * (maxv + 1)
tri2 = [0] * (maxv + 1)

# tri2 放所有元素
for x in nums:
    update(tri2, x, 1)

ans = 0
for num in nums:
    # 从右侧移除
    update(tri2, num, -1)

    leftLess = query(tri1, num - 1)
    leftMore = query(tri1, maxv) - query(tri1, num)
    rightLess = query(tri2, num - 1)
    rightMore = query(tri2, maxv) - query(tri2, num)

    ans += leftLess * rightMore + leftMore * rightLess
    # 加入左侧
    update(tri1, num, 1)

print(ans)

JavaScript

js 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

let inputLines = [];
rl.on("line", line => {
    inputLines.push(line.trim());
}).on("close", () => {
    const n = parseInt(inputLines[0]);
    const nums = inputLines[1].split(" ").map(Number);
    const maxv = Math.max(...nums);

    const tri1 = new Array(maxv + 1).fill(0);
    const tri2 = new Array(maxv + 1).fill(0);

    // 树状数组更新
    function update(tree, index, delta) {
        let n = tree.length - 1;
        while (index <= n) {
            tree[index] += delta;
            index += index & -index;
        }
    }

    // 树状数组查询前缀和
    function query(tree, index) {
        let res = 0;
        while (index > 0) {
            res += tree[index];
            index -= index & -index;
        }
        return res;
    }
    // 初始tri2 放所有元素
    for (let x of nums) update(tri2, x, 1);

    let ans = 0;
    for (let num of nums) {
        // 从右侧移除
        update(tri2, num, -1);

        let leftLess = query(tri1, num - 1);
        let leftMore = query(tri1, maxv) - query(tri1, num);
        let rightLess = query(tri2, num - 1);
        let rightMore = query(tri2, maxv) - query(tri2, num);

        ans += leftLess * rightMore + leftMore * rightLess;
        // 加入左侧
        update(tri1, num, 1);
    }

    console.log(ans);
});

Go

go 复制代码
package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

// 树状数组更新
func update(tree []int, index, delta int) {
    n := len(tree) - 1
    for index <= n {
        tree[index] += delta
        index += index & -index
    }
}

// 树状数组查询前缀和
func query(tree []int, index int) int {
    res := 0
    for index > 0 {
        res += tree[index]
        index -= index & -index
    }
    return res
}

func main() {
    reader := bufio.NewReader(os.Stdin)
    line1, _ := reader.ReadString('\n')
    n, _ := strconv.Atoi(strings.TrimSpace(line1))

    line2, _ := reader.ReadString('\n')
    parts := strings.Fields(line2)
    nums := make([]int, n)
    maxv := 0
    for i := 0; i < n; i++ {
        nums[i], _ = strconv.Atoi(parts[i])
        if nums[i] > maxv {
            maxv = nums[i]
        }
    }

    tri1 := make([]int, maxv+1)
    tri2 := make([]int, maxv+1)
    // 初始tri2 放所有元素
    for _, x := range nums {
        update(tri2, x, 1)
    }

    var ans int64 = 0
    for _, num := range nums {
         // 从右侧移除
        update(tri2, num, -1)

        leftLess := int64(query(tri1, num-1))
        leftMore := int64(query(tri1, maxv)-query(tri1, num))
        rightLess := int64(query(tri2, num-1))
        rightMore := int64(query(tri2, maxv)-query(tri2, num))

        ans += leftLess*rightMore + leftMore*rightLess
        // 加入左侧
        update(tri1, num, 1)
    }

    fmt.Println(ans)
}
相关推荐
无限码力3 天前
华为OD机试双机位C卷统一考试题库清单(持续收录中)以及考点说明
华为od·华为od机考·华为od机试·华为od机试双机位c卷·华为od机考双机位c卷·华为od双机位c卷·华为od上机考试 双机位c卷
无限码力3 天前
华为OD机试真题 - 没有回文串 (C++ & Python & JAVA & JS & GO)
华为od·华为od机试真题·华为od机试·od机考·华为od上机考试·华为od-没有回文串
无限码力6 天前
华为OD机考真题 -【测试用例执行计划】 (C++ & Python & JAVA & JS & GO)
华为od·华为od机考·华为od机试真题·华为od机试·华为od上机考试·华为od机考真题
开开心心_Every7 天前
无广告干扰:简单好用文字LOGO设计工具
xml·java·网络·数据库·华为od·华为云·excel
我是华为OD~HR~栗栗呀8 天前
(华为od)21届-Python面经
java·前端·c++·python·华为od·华为·面试
无限码力8 天前
华为OD机试双机位C卷 - 采样过滤 (C++ & Python & JAVA & JS & GO)
华为od·华为od机考·华为od机试·华为od机试双机位c卷·华为od上机考试·华为od机考真题·华为od机试-采样过滤
Tony_yitao12 天前
15.华为OD机考 - 执行任务赚积分
数据结构·算法·华为od·algorithm
无限码力14 天前
华为OD机试真题 - 最长广播响应 (C++ & Python & JAVA & JS & GO)
华为od·华为od机试·od机考·华为od上机考试真题·华为od机试-最长广播响应·华为od-最长广播响应
我是华为OD~HR~栗栗呀14 天前
(华为od)Python面经-20届
华为od