当前位置: 首页 > news >正文

[AtCoder Beginner Contest 396] F - Rotated Inversions

题目描述

题目链接

解法一、树状数组求逆序对

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long LL;

const int N = 2e5 + 10;
int n, m;
LL tr[N]; //tr[i]表示当前数组元素中值 <= i的有多少

int lowbit(int x) {
    return x & -x;
}

void add(int x, int c) {
    for(int i = x; i <= m; i += lowbit(i)) {
        tr[i] += c;
    }
}

LL sum(int x) {
    LL res = 0;
    for(int i = x; i > 0; i -= lowbit(i)) {
        res += tr[i];
    }
    return res;
}

int main() {
    cin >> n >> m;
    vector<int> a(n);
    
    for (int i = 0; i < n; i ++) {
        cin >> a[i];
    }
    
    //存储每个值在原数组中的位置
    vector<vector<int>> g(m);
    for (int i = 0; i < n; i ++) {
        g[a[i]].pb(i);
    }

    LL ans = 0;
    
    //利用树状数组进行数组初始时的逆序数(即k = 0时)
    //把值x存储到位置x + 1
    //那么对于当前位置为i的值a[i],其位置在之前并比其值大的数组元素有sum(m) - sum(a[i] + 1)
    //然后在把当前的值的个数增加存入到树状数组中, 即add(a[i] + 1, 1)
    for(auto x : a) { // x = a[i]
        ans += sum(m) - sum(x + 1);
        add(x + 1, 1);
    }
    
    cout << ans << '\n';

    for (int c = 1; c < m; ++c) {
        LL c1 = 0, c2 = 0;
        for (int idx = 0; idx < g[m - c].size(); idx ++) {
            //如果x + c = m,在这一轮中x的值将会变为(x + c) % m = 0,逆序数就可能会发生变化
            //分别讨论增加与减少的数量,其值分别为c1、c2
            //在某个变为0的数之前有多少不为0的数呢?值为g[m - c][idx] - idx(减去了跟它同组变为0且在它前面的数)
            c1 += g[m - c][idx] - idx;
            //同理需要计算,某个变为0的数之后有多少不为0的数。值为(n - 1) - g[m - c][idx] - (g[m - c].size() - 1 - idx)
            c2 += n - 1 - g[m - c][idx] - (g[m - c].size() - 1 - idx);
        }
        
        ans += c1 - c2;
        cout << ans << '\n';
    }
    
    return 0;
}

解法二、归并排序求逆序对

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long LL;

const int N = 2e5 + 10;
int n, m;
LL tr[N]; //tr[i]表示当前数组元素中值 <= i的有多少

int lowbit(int x) {
    return x & -x;
}

void add(int x, int c) {
    for(int i = x; i <= m; i += lowbit(i)) {
        tr[i] += c;
    }
}

LL sum(int x) {
    LL res = 0;
    for(int i = x; i > 0; i -= lowbit(i)) {
        res += tr[i];
    }
    return res;
}

//求解数组arr的逆序数 
LL merge(vector<int>& arr, int left, int right) {
    if (left >= right) {
        return 0;
    }
    
    int mid = (left + right) >> 1;
    LL res = merge(arr, left, mid) + merge(arr, mid + 1, right);

    vector<int> temp(right - left + 1);
    int i = left, j = mid + 1, k = 0;
    
    while(i <= mid && j <= right) {
        if(arr[i] <= arr[j]) {
            temp[k ++] = arr[i ++];
        } else {
            res += mid - i + 1;
            temp[k ++] = arr[j ++];
        }
    }
    
    while(i <= mid) temp[k ++] = arr[i ++];
    while(j <= right) temp[k ++] = arr[j ++];
    for (int p = 0; p < k; p ++) {
        arr[left + p] = temp[p];
    }
    
    return res;
}

int main() {
    cin >> n >> m;
    vector<int> a(n);
    
    for (int i = 0; i < n; i ++) {
        cin >> a[i];
    }
    
    //存储每个值在原数组中的位置
    vector<vector<int>> g(m);
    for (int i = 0; i < n; i ++) {
        g[a[i]].pb(i);
    }

    LL ans = merge(a, 0, n - 1);
    cout << ans << '\n';

    for (int c = 1; c < m; ++c) {
        LL c1 = 0, c2 = 0;
        for (int idx = 0; idx < g[m - c].size(); idx ++) {
            //如果x + c = m,在这一轮中x的值将会变为(x + c) % m = 0,逆序数就可能会发生变化
            //分别讨论增加与减少的数量,其值分别为c1、c2
            //在某个变为0的数之前有多少不为0的数呢?值为g[m - c][idx] - idx(减去了跟它同组变为0且在它前面的数)
            c1 += g[m - c][idx] - idx;
            //同理需要计算,某个变为0的数之后有多少不为0的数。值为(n - 1) - g[m - c][idx] - (g[m - c].size() - 1 - idx)
            c2 += n - 1 - g[m - c][idx] - (g[m - c].size() - 1 - idx);
        }
        
        ans += c1 - c2;
        cout << ans << '\n';
    }
    
    return 0;
}

相关文章:

  • Maven快速入门指南
  • 自回归模型(Autoregressive, AR)解读
  • 平时作业(偷懒)
  • 一、Jenkins简单配置(使用语言、凭证、SSH)
  • WinUI 3 支持的三种窗口 及 受限的窗口透明
  • FPGA设计时序约束用法大全保姆级说明
  • 基于LabVIEW的脚本化子VI动态生成
  • 将图片存储至阿里云 OSS
  • 2025数据存储技术风向标:解析数据湖与数据仓库的实战效能差距
  • 基于yolov8的土豆马铃薯叶子病害检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面
  • OSPF报文分析
  • 深度学习模型Transformer核心组件—前馈网络FFN
  • python如何把多维列表转换为dataframe
  • 【RabbitMQ | 第1篇】Erlang 和 RabbitMQ 的下载安装
  • easyconnect下服务器联网
  • 大白话JavaScript原型链查找机制与继承实现原理
  • Service与Ingress:如何将你的应用暴露给世界
  • 嵌入式 ARM Linux 系统构成(6):应用层(Application Layer)
  • VSTO(C#)Excel开发1:起步 示例项目
  • 【从零开始学习计算机科学】计算机组成原理(二)信息表示与编码
  • 15年全程免费,内蒙古准格尔旗实现幼儿园到高中0学费
  • 芬兰直升机相撞坠毁事故中五名人员全部遇难
  • 终于,俄罗斯和乌克兰谈上了
  • 俄乌谈判开始
  • 向猫学习禅修之后,你会发现将生活降格为劳作是多么愚蠢
  • 4台肺癌手术,2名“90后”患者,这届年轻人的肺怎么了?