归并排序求逆序对 //(洛谷)U4566 赛车比赛

https://www.luogu.org/problem/show?pid=U4566

显然的逆序对,以前只是嘴巴ac,这次终于打了出来。

逆序对其实就是冒泡排序的排序次数。。。。但是一般的排序时间复杂度为O(n^2),于是都会想到归并排序。。。

一、二路归并

  已知两个有序数组,将其归并为一个有序数组

  很显然,将首元素比较,小的扔进目的数组,最后把剩下的扔进去。。

1 int a[n],b[m],tmp[n+m];
2 int i=1,j=1,k=1;
3 while(i<=n&&j<=m)
4 {
5     if(a[i]<a[j])    tmp[k++]=a[i++];
6     else    tmp[k++]=b[j++];
7 }
8 while(i<=n)    tmp[k++]=a[i++];
9 while(j<=m) tmp[k++]=a[j++];

二路归并

二、归并排序

  运用二路归并来排序,可以达到O(nlogn);

  首先对于无序数组分治,使以中点为界的两个部分都变成有序的,最后进行归并。

  代码见下。

三、利用归并排序求逆序对

  进行归并排序时,如果后面部分首元素小于前部分首元素,则与前部分所有元素产生逆序。。。

  如果小于不会有逆序;

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#define LL long long
#define for1(i,n,m) for(int i=(n);i<=(m);i++)
#define for2(i,n,m) for(int i=(n);i>=(m);i--)
#define Maxn 305000
#define Maxe 506000
#define Inf 0x7fffffff
using namespace std;
int a[Maxn],tmp[Maxn];
LL ans;
struct edge{
    int x,v;
};
edge e[Maxn];
void Msort(int L,int R)//对区间(L,R)归并排序
{

    int mid;
    if(L>=R)
        return;        //边界
    mid=(L+R)>>1;        //以中点分治
    Msort(L,mid);
    Msort(mid+1,R);        //对俩部分依次归并排序
    int i=L,j=mid+1,k=L;
    while(i<=mid&&j<=R)        //归并
    {
        if(a[i]>a[j])
        {
            tmp[k++]=a[j++];
            ans+=mid-i+1;    //求逆序对数,注意这里是减i,不是L;
        }
        else
            tmp[k++]=a[i++];
    }
    while(i<=mid)    tmp[k++]=a[i++];
    while(j<=R)        tmp[k++]=a[j++];    //剩余的扔进辅助数组
    for1(t,L,R)
        a[t]=tmp[t];                    //更改原数组 

}
bool cmp(const edge&q,const edge&w)
{
    return q.x<w.x;
}
int main()
{
    ios::sync_with_stdio(0);
    int n;
    cin>>n;
    for1(i,1,n)
    {
        cin>>e[i].x>>e[i].v;
    }
    sort(e+1,e+n+1,cmp);
    for1(i,1,n)
    {
        a[i]=e[i].v;
    }
    Msort(1,n);
    cout<<ans;
    return 0;
}

归并排序求逆序对

时间: 2024-08-11 07:57:55

归并排序求逆序对 //(洛谷)U4566 赛车比赛的相关文章

归并排序求逆序对

归并排序求逆序对 by mps [1]什么是逆序对? 对于一个数列需要按从小到大排序,如果有ai,aj且满足ai>aj和i<j则ai,aj为一组逆序对 [2]如何求逆序对? 我们发现,我们可以暴力枚举i,j,然后逐一判断并累加答案即可,时间复杂度O(N2)        但是对于数据量大一点的题目,只有不断地TLE了→_→ [3]归并排序求逆序对 逆序对的定义(见[1])是一组本应该有序的序列中的逆序对,那么我们就想到了排序,但由于是要22匹配,我们又想到了归并排序 归并排序大致内容如下: 将

ZJNU 1247 归并排序求逆序对

逆序对——高级 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 118   Accepted: 28 Description 对于一个包含N个非负整数的数组A[1..n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对.  例如,数组(3,1,4,5,2)的逆序对有(3,1),(3,2),(4,2),(5,2),共4个. 求n个数中的逆序对个数. Input 第一

2014 HDU多校弟五场A题 【归并排序求逆序对】

这题是2Y,第一次WA贡献给了没有long long 的答案QAQ 题意不难理解,解题方法不难. 先用归并排序求出原串中逆序对的个数然后拿来减去k即可,如果答案小于0,则取0 学习了归并排序求逆序对的方法,可以拿来当模板 TVT 贴代码了: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostream&g

【BZOJ4769】超级贞鱼 归并排序求逆序对

[BZOJ4769]超级贞鱼 Description 马达加斯加贞鱼是一种神奇的双脚贞鱼,它们把自己的智慧写在脚上——每只贞鱼的左脚和右脚上各有一个数.有一天,K只贞鱼兴致来潮,排成一列,从左到右第i只贞鱼会在右脚写Ai,左脚上写上i:第二年,这K只贞鱼以右脚的数为第一关键字.左脚的数为第二关键字,从小到大排成一列.然后,它们决定重编号,从左到右第i只贞鱼会在右脚上写上左脚的数,在左脚上写i:第三年,它们按第二年的方法重排列.重编号......N年后,对于从左到右第i和第j贞鱼,若i<j且第i只

利用归并排序求逆序对

1.归并排序 先回顾一下归并排序 归并排序中归和并的意义: 归:递归.递归的将输入数组进行分割至长度为1. 并:合并.将各长度为1的数组顺序合并,完成归并排序. 归并排序的整体思想为分治,主体算法为: public void mergeSort(int[]arr, intbegin, intend) { if (begin != end) { int mid = (begin + end) /2; mergeSort(arr,begin, mid); mergeSort(arr,mid + 1,

【归并排序求逆序对】

[AC] 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 const int maxn=1e5+2; 6 int a[maxn]; 7 int tmp[maxn]; 8 int n; 9 ll ans; 10 void Merge(int l,int m,int r) 11 { 12 int i=l,j=m+1; 13 int k=l; 14 while(i<=m&&

归并排序求逆序对模板(未完待续)

归并排序求逆序对题目(持续更新) \(1.\) \(Ultra\) \(Quicksort\) (需要该篇博文的阅读密码) 归并排序求逆序对 细节:传参三个,左.中.右三端点,每次运算注意中端点总取左右端点和的一半:返回条件为左右端点相等,此时无需排序. \(View\) \(Code\) void msort(int l,int mid,int r) { if(l==r) return; msort(l,(l+mid)>>1,mid); msort(mid+1,(r+mid+1)>&g

poj2299(归并排序求逆序对)

题目链接:https://vjudge.net/problem/POJ-2299 题意:给定一个序列,每次只能交换邻近的两个元素,问要交换多少次才能使序列按升序排列. 思路:本质就是求逆序对.我们用归并排序求逆序对,这也是简单的cdq分治. #include<cstdio> #include<algorithm> #include<cstdlib> #include<cmath> using namespace std; typedef long long

归并排序+归并排序求逆序对(例题P1908)

归并排序(merge sort) 顾名思义,这是一种排序算法,时间复杂度为O(nlogn),时间复杂度上和快排一样 归并排序是分治思想的应用,我们先将n个数不断地二分,最后得到n个长度为1的区间,显然,这n个小区间都是单调的,随后合并相邻的两个区间,得到n/2个单增(减)的区间,随后我们继续合并相邻的两个区间,得到n/4个单增(减)的区间.... 每次合并操作的总时间复杂度为O(n),logn次合并用时O(logn),故总时间复杂度为O(nlogn) 合并操作比较好理解,就像下图这样二分区间即可