【蓝桥杯 / C++】星际争霸 — 字符串逆序对与大整数自定义排序

【蓝桥杯 / C++】星际争霸 --- 字符串逆序对与大整数自定义排序

1. 题目概述

在星际争霸的世界中,Protoss 种族需要对一组战斗力数值数组 aaa 进行排序。

为了减少灵能干扰,排序规则如下:

  1. 第一关键字 :按字符串内部的逆序对数量升序排序。
  2. 第二关键字 :若逆序对数量相同,按数值大小升序排序。

输入要求:

  • 数组长度 1≤n≤10001 \le n \le 10001≤n≤1000。
  • 战斗力数值 1≤ai≤1010001 \le a_i \le 10^{1000}1≤ai≤101000,可能包含前导零。
  • 输出时必须保留原前导零。

2. 解题思路与易错点

① 计算单个字符串的逆序对

  • 题目中字符串最大长度为 1000,O(L2)O(L^2)O(L2) 的双重循环暴力统计逆序对数量,单次最多约 1000×9992≈5×105\frac{1000 \times 999}{2} \approx 5 \times 10^521000×999≈5×105 次比较,在 1s 时间限制内完全可以通过。
  • 使用 long long 记录逆序对数量,防止溢出。

② 处理前导零与大整数比较(核心易错点)

  • 由于 ai≤101000a_i \le 10^{1000}ai≤101000,数值远超 long long 范围,必须用字符串比较。
  • 不能直接比较原字符串长度 :例如 "012"(长 3)与 "45"(长 2),直接比长度会误判为 45<1245 < 1245<12。
  • 解决方案 :利用 C++ std::string 的成员函数 find_first_not_of('0') 去除前导零。
    • 去除前导零后,先比较有效位数长度;
    • 若长度相同,再按字典序比较大小。

3. C++ 完整 AC 代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

// 存储结构体
struct change {
    string arr;     // 原始字符串(含前导零)
    long long sum;  // 内部逆序对数量
};

// 1. 计算字符串内部的逆序对数
long long sum_change(const string &t) {
    long long sum = 0;
    int len = t.size();
    for (int i = 0; i < len; i++) {
        for (int j = i + 1; j < len; j++) {
            if (t[i] > t[j]) {
                sum++;
            }
        }
    }
    return sum;
}

// 2. 去除前导零函数(用于大整数比较)
string remove_leading_zeros(const string &s) {
    auto k = s.find_first_not_of('0');
    if (k == string::npos) { // 全是 '0'
        return "0";
    }
    return s.substr(k);      // 从第一个非0字符截取到末尾
}

// 3. 自定义排序比较规则
bool cmp(const change &a1, const change &a2) {
    // 优先比较逆序对数量
    if (a1.sum != a2.sum) {
        return a1.sum < a2.sum;
    }  
    
    // 逆序对相同时,比较去除前导零后的实际数值
    string v1 = remove_leading_zeros(a1.arr);
    string v2 = remove_leading_zeros(a2.arr);
    
    if (v1.size() != v2.size()) {
        return v1.size() < v2.size(); // 位数多的数值大
    }
    return v1 < v2;                   // 位数相同按字典序比较
}

int main() {
    // 优化 I/O 效率
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    if (!(cin >> n)) return 0;

    vector<change> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i].arr;
        a[i].sum = sum_change(a[i].arr);
    }

    // 自定义排序
    sort(a.begin(), a.end(), cmp);

    // 输出排序后的原字符串
    for (const auto &m : a) {
        cout << m.arr << "\n";
    }

    return 0;
}

4. 关键 API 总结

  • s.find_first_not_of('0') :查找字符串 s 中第一个不是 '0' 的字符位置。若全部为 '0' 则返回 string::npos。
  • s.substr(pos) :截取从下标 pos 开始到末尾的子串。
相关推荐
行者全栈架构师1 小时前
【鸿蒙心迹】ArkUI 列表性能实战——为什么 200 条数据页面掉到 20fps,LazyForEach 怎么救(HarmonyOS 7.x)
前端·算法·架构
一碗甜汤ᐝ1 小时前
高级算法分析与设计 | 常见 NP-Complete 问题总结
算法·np-complete·算法分析与设计·np完备问题
垆边人似月.2 小时前
分割数组的最大值最小化(200分 / 二分答案 + 贪心)
数据结构·算法·排序算法
CQU_JIAKE2 小时前
10.7【A】
算法
Dfreedom.2 小时前
分类算法的统一视角:从方差最大化到概率建模再到损失函数
算法·支持向量机·分类
Nebula_g2 小时前
JavaSE加强:Commons-io框架
java·开发语言·算法·javase
梦帮科技3 小时前
【3.0修订版】音乐权利 NFT:MusicRightsNFT 的确权思想与授权关联
网络协议·算法·web3·区块链·密码学·智能合约·零知识证明
Dfreedom.3 小时前
基于PCA的光谱物质识别分析
算法
强化湿件的技术神甫3 小时前
KS检验和Lilliefors正态性检验方法
算法