携程0510笔试真题【单数组交换】

题目内容

游游有两个长度同为 nnn 的整数数组 aaa 和 bbb。她会对数组 aaa 执行标准冒泡排序来将其排成非递减序列(数组 bbb 始终不变):

  • 对于 i=1,2,...,n−1i = 1,2,\dots,n-1i=1,2,...,n−1,依次执行一趟扫描;
  • 在第 iii 趟中,按顺序检查 j=1,2,...,n−ij = 1,2,\dots,n-ij=1,2,...,n−i;
  • 若当前aj>aj+1a_j > a_{j+1}aj>aj+1,则交换这两个元素;否则不交换。
    每次实际发生交换时,其代价由当前位置对应的固定值 bj,bj+1b_j,b_{j+1}bj,bj+1 决定:
  • 若 bj≥bj+1b_j \ge b_{j+1}bj≥bj+1,则这次交换代价为 000;
  • 若 bj<bj+1b_j < b_{j+1}bj<bj+1,则这次交换代价为 111。
    请你计算,按照上述固定的冒泡排序过程把数组 aaa 排成非递减后,所有交换操作的总代价。

输入描述

每个测试文件均包含多组测试数据。第一行输入一个整数 T(1≤T≤105)T(1 \le T \le 10^5)T(1≤T≤105)代表数据组数。每组测试数据描述如下:

  • 第一行输入一个整数 n(1≤n≤2×105)n(1 \le n \le 2 \times 10^5)n(1≤n≤2×105)。
  • 第二行输入 nnn 个整数a1,a2,...,an(∣ai∣≤109)a_1,a_2,\dots,a_n(|a_i| \le 10^9)a1,a2,...,an(∣ai∣≤109)。
  • 第三行输入 nnn 个整数 b1,b2,...,bn(∣bi∣≤109)b_1,b_2,\dots,b_n(|b_i| \le 10^9)b1,b2,...,bn(∣bi∣≤109)。
    保证单个测试文件中所有测试数据的nnn之和不超过 5×1055 \times 10^55×105。

输出描述

对于每组测试数据,输出一行一个整数,表示按题目所述的固定冒泡排序过程将数组 aaa 排成非递减序列时,所有实际发生交换的总代价之和。。

样例1

输入

复制代码
2
4
2 1 2 1
3 1 2 2
6
17 15 12 10 18 3
1 5 1 3 1 2

输出

复制代码
1
7

说明

第一组数据中,按标准冒泡排序过程,恰好只会发生一次代价为 111 的交换,因此答案为 111。

第二组数据中,按照固定的冒泡排序顺序累计交换代价为777,因此答案为777。

思路和代码

本题主要是利用冒泡排序的交换路径唯一性, 从前往后扫描排序和每次从当前最大值开始进行交换排序本质上是同一个过程,只是观察角度不同。借助这个原理下面代码使用从当前最大值开始进行交换进行处理

  1. 假设当前已排序好的元素数量为x, 当前未排序中最大值maxValue的处于数组中位置为pos, 那么本次maxValue的交换路径为pos -> pos + 1, pos + 1 -> pos + 2.... , n-1-x-1 -> n-1-x

  2. 求上述1过程中交换路径的代价可以采用前缀和进行加速求解。使用优先队列维护当前最大的元素(值相同取位置更大的,保证稳定性),使用树状数组维护当前元素在"剩余数组"中的相对排名(求当前最大值)。

  3. 整体流程,重复执行以下操作

    • 取当前最大值
    • 用树状数组求它当前位置
    • 计算它经过的代价
    • 将其从树状数组和优先队列中删除。
  4. 累加所有代价和就是结果

算法时间复杂度为O(nlogn),空间复杂度为O(n)

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <queue>
using namespace std;
using ll = long long;

const ll INF = 1e18;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        vector<ll> a(n + 1);
        for (int i = 1; i <= n; ++i) cin >> a[i];
        vector<ll> b(n + 1);
        for (int i = 1; i <= n; ++i) cin >> b[i];
        
        // 边权 i交换是否计费
        vector<int> c(n, 0); 
        // 边权前缀和          
        vector<ll> pref_c(n, 0);       
        for (int i = 1; i < n; ++i) {
            c[i] = (b[i] < b[i+1]) ? 1 : 0;
            pref_c[i] = pref_c[i-1] + c[i];
        }
        
        // 最大值优先,值相同,位置大的优先
        priority_queue<pair<ll,int>> pq;
        
        for (int i = 1; i <= n; i++) {
            pq.push({a[i], i});
        }

        // 树状数组 维护当前元素相对位置
        vector<int> fenw(n + 2, 0);
        // 
        auto fenw_add = [&](int idx, int delta) {
            while (idx <= n) {
                fenw[idx] += delta;
                idx += idx & -idx;
            }
        };

        auto fenw_sum = [&](int idx) {
            int res = 0;
            while (idx > 0) {
                res += fenw[idx];
                idx -= idx & -idx;
            }
            return res;
        };

        for (int i = 1; i <= n; ++i) fenw_add(i, 1);
         
        ll ans = 0;
        int cur_len = n;
        for (int step = 0; step < n; ++step) {
            auto [val, pos] = pq.top();          // 当前最大值及其原始位置
            pq.pop();
            int rank = fenw_sum(pos);          // 在当前未排序数组中的排名
            // 贡献从 rank 到 cur_len-1 的边权总和
            ans += pref_c[cur_len - 1] - pref_c[rank - 1];
            // 删除该元素
            fenw_add(pos, -1);
            --cur_len;
        }
        cout << ans << '\n';
    }
    return 0;
}
相关推荐
BlockWay2 小时前
WEEX Labs 周度观察:微软-OpenAI 合作调整与AI 多云趋势
大数据·人工智能·算法·安全·microsoft
风筝在晴天搁浅2 小时前
快手 CodeTop LeetCode 224.基本计算器
数据结构·算法·leetcode
Smoothcloud润云2 小时前
5大功能精修,重构AI算力使用体验!
java·人工智能·windows·算法·重构·编辑器·sublime text
计算机安禾2 小时前
【算法分析与设计】第41篇:确定性与非确定性多项式时间:P与NP的形式化
算法
leo__5203 小时前
随机接入退避算法过程模拟实现
网络·算法
-To be number.wan3 小时前
算法日记 | STL- sort排序
c++·算法
玖釉-3 小时前
Vulkan 中 Shader 的 vert、frag、mesh、comp 全面解析:作用、关系、特点与工程实践
开发语言·c++·windows·算法·图形渲染
智者知已应修善业3 小时前
【51单片机2个外部中断切换LED花样】2024-1-3
c++·经验分享·笔记·算法·51单片机
8Qi84 小时前
LeetCode 31:下一个排列(Next Permutation)—— 完整题解笔记 ✅
笔记·算法·leetcode·指针·思维·排列