浅谈逆序对

$$传送门qwq$$


题目描述

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

最近,\(TOM\)老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:

对于给定的一段正整数序列,逆序对就是序列中\(a_i\)>\(a_j\)且\(i\)<\(j\)的有序对。

知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。

Update:数据已加强。


输入输出格式

输入格式:

第一行,一个数\(n\),表示序列中有\(n\)个数。

第二行\(n\)个数,表示给定的序列。序列中每个数字不超过\(10^9\)

输出格式:

给定序列中逆序对的数目。


本蒟蒻今天学习了树状数组,今天来更新啦

思路1

逆序对是什么东西呢,在题目已经给出介绍了

对于给定的一段正整数序列,逆序对就是序列中\(a_i\)>\(a_j\)且\(i\)<\(j\)的有序对。

比如你有一个\(a\)数组,如果在这个数组中中\(a[i]\)>\(a[j]\)并且\(i\)<\(j\),我们就称它是一个逆序对

这个题就是要求我们求出输入的数中逆序对的数量

求逆序对的方法有很多种,可以用树状数组,也可以用线段树,但由于本蒟蒻没有学过这俩玩意儿,所以只会用归并排序,那么归并排序又是什么呢

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

可以来这里理解一下什么是归并排序

那么归并排序有什么优点呢?

* 归并排序是利用归并的思想实现的排序方法,该算法采用经典的分治策略

* 归并排序是稳定排序

* 归并排序的最好,最坏,平均时间复杂度均为O(\(nlogn\))。

如何实现求逆序对??

假设我们手头有两个已经从小到大排好序的数组,且他们分别是原来的一段大数组的前半段和后半段,现在我们的比较到了X,Y位置

假使X>Y则其必然构成一对逆序对,与此同时我所画出的红色的这一段的的数均大于Y,所以逆序对的数量就要加上这一段的长度

而对整个数组都归并排序完毕后最终就可以得到逆序对的和

代码

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std; int n;
long long ans;
int a[5000007],b[5000007]; void sort(int l,int r) {
if(l==r)return;
int m=(l+r)>>1;
sort(l,m);
sort(m+1,r);
int i=l,j=m+1,k=l;
while(i<=m&&j<=r) {
if(a[i]<=a[j])b[k++]=a[i++];
else ans+=m-i+1,b[k++]=a[j++];
}
while(i<=m)b[k++]=a[i++];
while(j<=r)b[k++]=a[j++];
for(i=l; i<=r; ++i)a[i]=b[i];
} inline int read() {
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-')w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
s=s*10+(ch-'0');
ch=getchar();
}
return s*w;
} int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++) {
a[i]=read();
}
sort(1,n);
printf("%lld",ans);
return 0;
}

思路2

我们可以用树状数组实现

离散化一下,直接将输入的数变为负数,在之后按价值从小到大排序,排完序之后再用树状数组维护,并每次把这个数的位置加入到树状数组中

因为是排完序之后,所以之前加入的一定比后加入的大,然后在查询当前这个数前面位置的数(是前面位置的数,要当前这个数减1),就是逆序对的个数了

代码

#include<bits/stdc++.h>
#define N 500110
#define lowbit(i) i&-i
using namespace std; int n,a[N],b[N],t[N];
long long ans=0; inline int read(){
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return x*f;
} inline void insert(int x){
for(int i=x;i<=n;i+=lowbit(i)){
t[i]++;
}
} inline int find(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i)){
ans+=t[i];
}
return ans;
} int main(){
n=read();
for(int i=1;i<=n;i++)a[i]=b[i]=-read();
sort(b+1,b+1+n);
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+n+1,a[i])-b;
}
for(int i=1;i<=n;i++){
ans+=find(a[i]-1);
insert(a[i]);
}
cout<<ans<<'\n';
return 0;
}

洛谷 P1908 逆序对的更多相关文章

  1. 洛谷P1908 逆序对

    P1908 逆序对 2.2K通过 4.4K提交 题目提供者该用户不存在 标签云端 难度普及/提高- 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 归并排序党注意了!数组要开… ...

  2. 洛谷P1908 逆序对【递归】

    题目:https://www.luogu.org/problemnew/show/P1908 题意:给定一个数组,求逆序对个数. 思路: 是一个很经典的题目了.通过归并排序可以求逆序对个数. 现在有一 ...

  3. 洛谷 P1908 逆序对 Label:归并排序||树状数组 不懂

    题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定 ...

  4. 洛谷P1908 逆序对 [权值线段树]

    题目传送门 逆序对 题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的 ...

  5. 洛谷—— P1908 逆序对

    https://www.luogu.org/problem/show?pid=1908 题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏, ...

  6. 洛谷 P1908 逆序对(归并排序解法)

    树状数组解法:https://www.cnblogs.com/lipeiyi520/p/10846927.html 题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不 ...

  7. 洛谷 P1908 逆序对(树状数组解法)

    归并排序解法:https://www.cnblogs.com/lipeiyi520/p/10356882.html 题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不 ...

  8. 洛谷P1908 逆序对(归并排序)

    题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定 ...

  9. 洛谷 P1908 逆序对 题解

    每日一题 day43 打卡 Analysis 因为数据规模,所以我们需要对其进行离散化,新创一个数组a里面来放在我们的初始序列中在这个位置上的数是第几大的这里还要用一个小技巧排序,关于离散化的技巧我们 ...

随机推荐

  1. 【Java基础】【12String类】

    12.01_常见对象(Scanner的概述和方法介绍)(掌握) A:Scanner的概述 B:Scanner的构造方法原理 Scanner(InputStream source) System类下有一 ...

  2. AppBoxFuture(一): Hello Future!

      AppBoxFuture是一个快速应用框架(Rapid Application Framework),是作者十几年从事信息化建设的经验结晶.框架具备以下一些特色: 极简的分布式系统架构 根据需要可 ...

  3. redis常见错误处理

    --1]当内存不足引起  redis出错 先尝试下列语句,指定redis使用内存 redis-server.exe redis.windows.conf --maxheap 200mredis-ser ...

  4. DataTable转换成List集合,传递到HTML页面

    public string GetPwd(string str) { var dt= bll.Gets(str); List<string> list = new List<stri ...

  5. 轻松搞定RocketMQ入门

    RocketMQ是一款分布式.队列模型的消息中间件,具有以下特点: 能够保证严格的消息顺序 提供丰富的消息拉取模式 高效的订阅者水平扩展能力 实时的消息订阅机制 亿级消息堆积能力 RocketMQ网络 ...

  6. java日期转化,三种基本的日期格式

    import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public cl ...

  7. springboot之配置文件

    springboot在加载配置文件的时候是有先后顺序的,了解加载配置文件的先后顺序,可以减少编写程序出现错误 1 springboot加载配置文件的先后顺序如下: SpringApplication将 ...

  8. Chrome下面查看placeholder的样式

    在Chrome下面默认是看不到placeholder的样式的 我们可以通过在当前页面的开发者工具里面的settings 勾选下面这个选项,就可以看到了 下面是效果

  9. 博弈论进阶之Every-SG

    Every-SG 给定一张无向图,上面有一些棋子,两个顶尖聪明的人在做游戏,每人每次必须将可以移动的棋子进行移动,不能移动的人输 博弈分析 题目中的要求实际是"不论前面输与否,只要最后一个棋 ...

  10. Windchill基本业务对象-文档

    文档的类型: (1)WTDocumetManster :是文档的主要信息,一个文档只有一条记录:(2)WTDocument:是文档小版本记录,每一个文档小版本都有一条记录: 备注:(1)文档大版本记录 ...