蓝桥杯练习系统:试题 算法提高 逆序对

试题 算法提高 逆序对

内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s

问题描述

SORT公司是一个专门提供排序服务的公司,该公司的宗旨是:“顺序是美丽的”。他们的工作是通过一系列移动,将某些物品按顺序摆好。他们的服务是通过工作量来计算的,即移动物品的次数。所以,在工作前必须先考察工作量,以便向客户提出收费数目。
  用户并不需要知道精确的移动次数,实质上,大多数人都是凭感觉来认定这一列物品的混乱程度。根据SORT公司的经验,人们一般是根据“逆序对”的数目多少来称呼这一序列的混乱程度。假设将序列中第I件物品的参数定义为Ai,那么排序就是将A1,……An从小到大排序。若i<j且Ai>Aj,则<i,j>就为一个“逆序对".
  SORT公司请你写一个程序,在尽量短的时间内统计出”逆序对“的数目。
输入格式
  第1行为n(1<=n<=100000)
  接下来N行,每行一个长整数型范围内的整数。
输出格式
  一个整数,为逆序对的数目。
样例输入
5
3
1
4
5
2
样例输出
4

理解

1.逆序对:设 A 为一个有 n 个数字的有序集 (n>1),其中所有数字各不相同。如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 A[i], A[j]> 这个有序对称为 A 的一个逆序对,也称作逆序数。
2.本题目用归并算法,在每层递归中累加逆序对的数量

提交代码

#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],tmp[N];
int merge_sort(int a[],int l,int r){
	if(l>=r)return 0;
	int mid=l+r>>1;
	int ret=merge_sort(a,l,mid)+merge_sort(a,mid+1,r);
	int x=l,y=mid+1,k=0;
	while(x<=mid&&y<=r)
		if(a[x]<=a[y])tmp[k++]=a[x++];
		else {
			tmp[k++]=a[y++];ret+=mid+1-x;
		}
	while(x<=mid)tmp[k++]=a[x++];
	while(y<=r)tmp[k++]=a[y++];
	for(int i=l,j=0;i<=r;i++,j++)a[i]=tmp[j];
	return ret;
}
	
int main(){
	int n;cin>>n;
	for(int i=0;i<n;i++)cin>>a[i];
	cout<<merge_sort(a,0,n-1);
	return 0;
}

但是数据大小有点问题,改成long long ,龙龙🐉这样就过了
在这里插入图片描述

#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int a[N],tmp[N];
ll merge_sort(int a[],int l,int r){
	if(l>=r)return 0;
	int mid=l+r>>1;
	ll ret=merge_sort(a,l,mid)+merge_sort(a,mid+1,r);
	int x=l,y=mid+1,k=0;
	while(x<=mid&&y<=r)
		if(a[x]<=a[y])tmp[k++]=a[x++];
	
		else {
			tmp[k++]=a[y++];ret+=mid+1-x;
		}
	while(x<=mid)tmp[k++]=a[x++];
	while(y<=r)tmp[k++]=a[y++];
	for(int i=l,j=0;i<=r;i++,j++)a[i]=tmp[j];
	return ret;
}
	
int main(){
	int n;cin>>n;
	for(int i=0;i<n;i++)cin>>a[i];
	cout<<merge_sort(a,0,n-1);
	return 0;
}

总结:

归并算法来源于acwing,算法模板如下:

#include <iostream>

using namespace std;

typedef long long ll;//long long比较长写起来比较麻烦,故用typedef

ll merge_sort(int l, int r);//该函数的功能为直接返回逆序对个数

const int N = 1e5 + 10;

int q[N], n, a[N];

int main()
{
    cin >> n;
    
    for (int i = 0; i<n; i++) cin >> q[i];
    
    cout << merge_sort(0, n - 1) <<endl;
    
    return 0;
}

ll merge_sort(int l, int r)
{
    if (l == r) return 0;//递归的终点
    
    int mid = l + r >> 1;
    ll count = merge_sort(l, mid) + merge_sort(mid + 1, r);//将左右逆序对数量先加总
    
    int i = l, j = mid + 1, k = 0;
    while(i<=mid && j<=r)
    {
        if (q[i]<=q[j]) a[k++] = q[i++];
        else 
        {
            count = count + (mid + 1 - i);//由上图可知此处右侧每个数能与左侧构成的逆序对有mid + 1 -i个
            a[k++] = q[j++];
        }
    }
    while(i<=mid) a[k++] = q[i++];//扫尾
    while(j<=r) a[k++] = q[j++];//扫尾
    
    for (i = l, k = 0; i<=r;) q[i++] = a[k++];//归还数组元素
    
    return count;//返回逆序对个数
}//该代码引用AcWing网站的代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

热血少年鸡小龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值