首页 > 编程语言 >[算法日常] 逆序对

[算法日常] 逆序对

时间:2024-10-17 23:00:17浏览次数:1  
标签:return ljl sum ans 算法 日常 rc 逆序

[算法日常] 逆序对

定义

在一个长度为 \(n\) 的数组 \(a\) 中,若存在 \(\forall 1\le i,j\le n\),使得 \(a_i>a_j\) ,则称 \(<a_i,a_j>\) 为一对逆序对。

举个例子,一个长度为 \(5\) 的数组为:

1 5 3 6 4

则存在 \(3\) 个逆序对,分别是 \(<5,3>,<5,4>,<6,4>\)。

解法

F1:

显然,可以枚举 \(\forall 1\le i,j\le n\),若满足 \(a_i>a_j\),则答案 \(+1\)。

#include<bits/stdc++.h>
using namespace std;
#define ljl long long
const ljl N=5e5+5;
ljl n,a[N],ans;
int main(){
    scanf("%lld",&n);
    for(ljl i=1;i<=n;i++)
        scanf("%lld",&a[i]);
   	for(ljl i=1;i<=n;i++)
        for(ljl j=i+1;j<=n;j++)
            if(a[i]>a[j])
                ++ans;
   	printf("%lld\n",ans);
    return 0;
}

现场手打的代码,没有编译过

F2:重点:利用可维护区间的数据结构

首先再次分析题目。

不难想到,可以记录所有比 \(a_i\) 大的数字个数,最后 \(a_i\)​ 对答案的贡献即为比它大的数字个数。

不妨用 \(bkt_i\) 表示 \(i\) 出现的次数(类似于桶)。

因为是求所有 \(\ge a_i\) 的值,所以就可以将数组排序,然后统计 \(i\sim n\) 的数字个数和。

那么就扯上了区间问题。

那么网上大多数人都是用树状数组来进行区间维护。而我——用线段树!!!!

万能的线段树,接受我的膜拜!!!!!

话说我咋还没有发表过关于线段树的博客啊……最近学业有点忙,待更新!!!

正题。

还有一个问题,就是关于桶。

如果 \(a_i\) 的范围过大?空间肯定爆炸。

这时候,离散化就出场了。

离散化:

对于有些问题,我们仅需要知道其值与其他数字的关联(比如大小排序),就可以将其下标赋值为排序后的排名(奇怪的修辞)。

利用区间数据结构查询区间和

综上所述,可以想到用 \(b\) 表示原数组,\(id_i\) 表示在原数组中第 \(i\) 小的数,最后统计区间 \(a_i\) 的值即可。

例题

洛谷 P1908 逆序对

代码实现

#include<bits/stdc++.h>
using namespace std;
#define ljl long long
#define lc p<<1
#define rc p<<1|1
const ljl N=5e5+5;
ljl n,ans,id[N],b[N];
struct SMT{
	ljl l,r,sum;
}e[N<<4];
void build(ljl l,ljl r,ljl p)//线段树建树
{
	e[p].l=l;e[p].r=r;
	if(l==r)
	{
		e[p].sum=0;
		return;
	}
	ljl mid=l+r>>1;
	build(l,mid,lc);
	build(mid+1,r,rc);
	e[p].sum=e[lc].sum+e[rc].sum;
	return;
}
void add(ljl x,ljl val,ljl p)//遇到了离散化后下标为x的数,将其个数+1
{
	if(e[p].l==e[p].r)
	{
		e[p].sum++;
		return;
	}
	ljl mid=e[p].l+e[p].r>>1;
	if(x<=mid)
		add(x,val,lc);
	if(x>mid)
		add(x,val,rc);
	e[p].sum=e[lc].sum+e[rc].sum;
	return;//与线段树正常的单点修改大同小异
}
ljl query(ljl l,ljl r,ljl p)//查询区间
{
	if(l<=e[p].l&&e[p].r<=r)
		return e[p].sum;
	ljl ans=0,mid=e[p].l+e[p].r>>1;
	if(l<=mid)
		ans+=query(l,r,lc);
	if(r>mid)
		ans+=query(l,r,rc);
	return ans;
}
int main(){
	scanf("%lld",&n);
	for(ljl i=1;i<=n;i++)
	{
		scanf("%lld",&b[i]);//原数组
		id[i]=b[i];//开始先赋值为原数组
	}
	sort(b+1,b+n+1);
	unique(b+1,b+n+1);//去重,是离散化的一个重要部分
	for(ljl i=1;i<=n;i++)
	{
		ljl pos=lower_bound(b+1,b+n+1,id[i])-b;
        //lower_bound:查询区间内第一个大于等于它的元素,因为是二分查找,所以时间是log n。
		id[i]=pos;
	}
	build(1,n,1);
	for(ljl i=1;i<=n;i++)
	{
		ans=ans+query(id[i]+1,n,1);//查询id[i]+1 ~ n 的区间
		add(id[i],1,1);
	}
	printf("%lld\n",ans);
	return 0;
}

预祝大家 CSP-J/S 2024 RP++!!!

标签:return,ljl,sum,ans,算法,日常,rc,逆序
From: https://www.cnblogs.com/Atserckcn/p/18473279

相关文章

  • STL容器和算法
    1、C++的STL介绍(内存管理、allocator、函数、实现机理、多线程实现)STL一共提供六大组件,包括容器、算法、迭代器、仿函数、配接器和配置器,彼此可以组合套用。容器通过配置器取得数据存储空间,算法通过迭代器存取容器内容,仿函数可以协助算法完成不同的策略变化,配接器可以应用于容......
  • 武汉大学卫星导航算法程序设计——解码与数据获取
    还在为解码发愁吗?面对二进制文件还是无从下手吗?一篇文章帮你搞定。我们从接收机获取的数据并不是rinex格式的文件,而是NovAtel数据格式的二进制文件。我们需要从文件中提取出我们需要的导航数据,也就是解码的过程。废话不多说,我们直接开始讲解。一、Binary数据头格式请不要使......
  • 排序算法 - 快速排序
    排序算法-快速排序  概要  快速排序(Quicksort)是对冒泡排序算法的一种改进。快速排序是一种基于分而治之的排序算法。  它的基本思想是:选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小。然后,再按......
  • 【算法】C++中的二分查找
    ......
  • 代码随想录算法训练营 | 1143.最长公共子序列,1035.不相交的线,53. 最大子序和,392.判断
    1143.最长公共子序列题目链接:1143.最长公共子序列文档讲解︰代码随想录(programmercarl.com)视频讲解︰最长公共子序列日期:2024-10-17想法:这里的子序列不要求连续了,dp[i][j]要表示为在text1[0,i-1]和text2[0,j-1]的范围里,最长的公共子序列长度,-1同样是为了初始化方便,如果te......
  • 吴恩达深度学习笔记(4)---加速神经网络训练速度的优化算法
    机器学习的应用是一个高度依赖经验,不断重复的过程,需要训练很多模型才能找到一个确实好用的。小批量梯度下降算法:矢量化可以有效计算m个算例而不需要for循环,因此我们需要将所有的训练样例放入巨型矩阵中。但是当数据量超大时,计算时间仍需很久,可以考虑将训练集分为微小的训练集......
  • (算法)最⻓湍流⼦数组————<动态规划>
    1.题⽬链接:978.最⻓湍流⼦数组2.题⽬描述:3.解法(动态规划):算法思路:1.状态表⽰:我们先尝试定义状态表⽰为:dp[i]表⽰「以i位置为结尾的最⻓湍流数组的⻓度」。 但是,问题来了,如果状态表⽰这样定义的话,以i位置为结尾的最⻓湍流数组的⻓度我们没法从之前的状态推导出......
  • (算法)等差数列划分————<动态规划>
    1.题⽬链接:413.等差数列划分2.题⽬描述:3.解法(动态规划):算法思路:1.状态表⽰:由于我们的研究对象是「⼀段连续的区间」,如果我们状态表⽰定义成[0,i]区间内⼀共有多少等差数列,那么我们在分析dp[i]的状态转移时,会⽆从下⼿,因为我们不清楚前⾯那么多的「等差数列都在什......
  • 图论day64 :最短路径算法 | SPFA(Bellman_ford的队列优化版)、城市间货物运输 I、Ⅱ、Ⅲ
    图论day64:最短路径算法|SPFA(Bellman_ford的队列优化版)、94.城市间货物运输I(卡码网)【SPFA算法+邻接表优化】、95.城市间货物运输II(判断负权回路)、96.城市间货物运输III【已知有负权回路,该如何计算】、Bellman_ford算法思维导图汇总SPFA(Bellman_ford的队列优化版)94......
  • 从单细胞和空间转录组学推断模式驱动的细胞间流动(Flowsig)--生信算法笔记
    **Inferringpattern-drivingintercellularflowsfromsingle-cellandspatialtranscriptomics**Almet,A.A.,Tsai,YC.,Watanabe,M.etal.Inferringpattern-drivingintercellularflowsfromsingle-cellandspatialtranscriptomics.NatMethods21,1806......