P1908 逆序对

本文介绍了如何计算逆序对,分别通过暴力求解、分治策略结合归并排序以及使用树状数组的方法,详细解析了思路和实现代码,其中分治算法和树状数组降低了时间复杂度。
摘要由CSDN通过智能技术生成

题目描述

P1908 逆序对
猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。

最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai>aj

且 i<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。

思路

  • 暴力求解
    如果暴力求解,那么思路很简单
    从后往前找,先从末尾开始
    拿当前这个数与之后的数比较
    如果比当前数小就直接ans++,
    最后枚举完了,就是最终答案
    时间复杂度 O(n*n) TLE

  • 分治
    如果求一个区间内的逆序对,是不是可以转化为求两个区间内的逆序对
    (那么就会有同学问,你本来一个区间内的逆序对,可能会拆开啊,计算时不会被计算到啊?)
    这个问题很简单嘛,你直接再拿两个区间的数再比较就彳亍
    实现:归并排序
    这时又有一个问题,归并排序,是会排序的啊,会打乱原来顺序啊
    其实并不影响,因为比较的是两个区间内的各个数的大小,而左区间的下标一定比右区间的下标小,即使区间内排了序也不影响
    遗留问题:既然利用归并排序,如果每次像暴力一样比较,那也会使时间复杂度变为O(n*n),所以如果计算是关键
    其实归并时,就在比较两个数的大小,如果左区间的数一直小于等于右区间的数,直到碰到右区间的一个数小于左区间的数,是不是之后的所有数,即[i,mid]的数(i为左区间位置 都与当前这个数互为逆序对,所以此时答案就可以直接加上前面剩下左区间的个数

  • 树状数组
    可能有同学就会问了,树状数组不是用来计算区间和吗,这个逆序对和区间合有毛的关系?
    这里就很巧妙了
    回到暴力的想法,有两步
    第一步,从后往前枚举
    第二步,拿当前这个数与前面的所有数一一比较
    第一步,不能再优化了(你每个都不枚举一下,答案就会有错)
    第二步,其实是在寻找比 枚举到当前数 小的数,这里就可以树状数组来查询,每次被枚举后的数需要更行sum[1,a[i] ]
    时间复杂度O(n*logn)
    注意:如果a[i]的范围过大 需要离散化
    当然其实也可以从前往后枚举,读者可以自行思考

代码

归并排序

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;
int n;
const int maxn=5*1e5+100;
int m[maxn];
int mn[maxn];
long long ans=0;
void msort(int a,int b){
   //因为左区间的下标始终大于右区间下标,所以就算排序了也不影响比较大小 </
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值