codevs【1688】求逆序对

题目描述
给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目
数据范围:N<=10^5, Ai<=10^5。时间限制为1s。

输入描述
第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数。

输出描述
所有逆序对总数.

样例输入
4
3
2
3
2

样例输出
3

分析
求逆序数主要有两种方法,归并排序和树状数组。
树状数组求逆序数讲解链接 https://www.cnblogs.com/xiongmao-cpp/p/5043340.html
方式一:非递归形式的归并排序

#include<iostream>
using namespace std;
#define N 100000 + 10
#define ll long long
ll ans;
void merge(int a[],int b[],int s,int m,int t)
{ 
	int i = s,j = m + 1,k = s;
	while(i <= m && j <= t) {
		if(a[i] <= a[j]) b[k++] = a[i++];
		else {
			b[k++] = a[j++];
			ans += m - i + 1;//可以求逆序数
		}
	}
	while(i <= m) b[k++] = a[i++];//收尾处理
	while(j <= t) b[k++] = a[j++];
}
void mergePass(int a[],int b[],int n,int h)//一次归并排序
{
	int i = 0;//下标从0开始 
	while(i <= n - 2 * h + 1) {//待排序记录至少有两个长度为h的子序列
### 关于信息学奥赛一本通中逆序对的解题方法 #### 归并排序算法实现逆序对量 归并排序是一种分治算法,在排序过程中可以统计组中的逆序对目。通过每次合并两个有序序列时计算跨越这两个子序列之间的逆序对,最终得到整个组内的全部逆序对。 当左半部分元素大于右半部分当前处理位置上的元素,则说明存在若干个逆序对,这些逆序对量等于左边剩余未比较过的元素个。这是因为对于每一个这样的左侧较大值而言,右侧已经遍历到的位置之前的所有值都小于它,从而构成一组新的逆序关系[^1]。 ```cpp #include <iostream> using namespace std; typedef long long ll; ll cnt; // 记录逆序对 const int maxn = 5e5 + 7; int a[maxn], tmp[maxn]; void merge(int l, int mid, int r){ int i=l,j=mid+1,k=l; while(i<=mid && j<=r){ if(a[i]<=a[j]){ tmp[k++]=a[i++]; }else{ cnt += (mid-i+1); // 统计逆序对 tmp[k++] = a[j++]; } } while(i<=mid)tmp[k++] = a[i++]; while(j<=r)tmp[k++] = a[j++]; for(int p=l;p<=r;++p)a[p]=tmp[p]; } void mergesort(int l,int r){ if(l>=r)return ; int m=(l+r)>>1; mergesort(l,m); mergesort(m+1,r); merge(l,m,r); } ``` 此代码实现了基于归并排序来解决逆序对问题的方法。`cnt`变量用于累计所有的逆序对目;函`merge()`负责将两个已排序区间合并的同时完成跨区间的逆序对检测工作;而`mergesort()`则是递归调用来分别对左右两部分进行排序以及后续的合并操作[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值