【SGU 180】Inversions —— 归并排序或树形数组计算逆序对

原题链接

180. Inversions

time limit per test: 0.25 sec.

memory limit per test: 4096 KB

input: standard

output: standard

There are N integers (1<=N<=65537) A1, A2,.. AN (0<=Ai<=10^9). You need to find amount of such pairs (i, j) that 1<=i<j<=N and A[i]>A[j].

Input

The first line of the input contains the number N. The second line contains N numbers A1...AN.

Output

Write amount of such pairs.

Sample test(s)

Input


5 2 3 1 5 4

Output


3

解题报告:

逆序对!经典的算法之一!

方法一是利用归并排序来计算,简单修改merge即可统计逆序对的数量。

方法二是采用离散化+树形数组(或者线段树)

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

long long reverse_pair(int a[],int n)
{
    if(n<2) return 0;

    long long sum=0 , mid=n/2;
    sum += reverse_pair(a,mid);
    sum += reverse_pair(a+mid,n-mid);

    int *b=new int[n];
    memcpy(b,a,n*sizeof(int));

    int i=0,j=mid; int k=0;
    for(;i<mid && j<n;++k)
        if(b[i]<=b[j]) {a[k]=b[i];++i;}
        else {a[k]=b[j];++j;sum+=(mid-i);}

    if(j==n) for(;i<mid;++i,++k) a[k]=b[i];
    else     for(;j<n;++j,++k) a[k]=b[j];

    delete [] b;
    return sum;
}

int C[65537+10],n;
inline int lowbit(int x){return x&(-x);}
long long sum(int k){
    long long sum=0;
    while(k>0) {
        sum+=C[k]; k-=lowbit(k);
    }
    k=n;
    while(k>0) {
        sum-=C[k]; k-=lowbit(k);
    }
    return -sum;
}
void modify(int k){
    while(k<=n){C[k]+=1;k+=lowbit(k);}
}

int main()
{
     int a[65537+10],b[65537+10];
     while(cin>>n){
//        方法1:归并排序
//        for(int i=0;i<n;++i)
//            cin>>a[i];
//        cout<<reverse_pair(a,n)<<endl;

//        方法2:离散化+树形数组
        for(int i=0;i<n;++i)  cin>>a[i];
        memcpy(b,a,n*sizeof(int));

        // 离散化
        sort(a,a+n);
        int SIZE=unique(a,a+n)-a;
        for(int i=0;i<n;++i) b[i]=lower_bound(a,a+SIZE,b[i])-a+1;

        // 树形数组
        long long ans=0; memset(C,0,sizeof(C));
        for(int i=0;i<n;++i){
            modify(b[i]);
            ans+=sum(b[i]);
        }
        cout<<ans<<endl;
     }
}
时间: 2024-10-27 18:36:16

【SGU 180】Inversions —— 归并排序或树形数组计算逆序对的相关文章

Ultra-QuickSort (poj 2299 归并排序 || 树状数组 求逆序对)

Language: Default Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 45751   Accepted: 16615 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct i

用树状数组处理逆序对[数据结构][树状数组]

逆序对 ——!x^n+y^n=z^n 可以到这里[luogu]: https://www.luogu.org/problem/show?pid=1908 题意:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对.知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目. 假如为这些数为: 8 2 3 1 7 如果我们把数一个个加进来,用一个数组a[i]统计i出现了几次. a的初始状态: 8加进来后: 由于不存在比8大的数,说明没有产生逆序对 2加进来后: 统计比2大

Day2:T4用树状数组求逆序对

T4: 用树状数组求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I B[J]>=B[I] 之后就是求逆序对的事情了 然后这里学一下用树状数组的方法 原理是:树状数组是用来求区间和的是吧 就是按权值的区间统计那么可以BIT维护...然后扫一遍 也就是计算有多少个逆序对 按权值的区间统计就是记录数的个数

SGU180(树状数组,逆序对,离散)

Inversions time limit per test: 0.25 sec. memory limit per test: 4096 KB input: standard output: standard There are N integers (1<=N<=65537) A1, A2,.. AN (0<=Ai<=10^9). You need to find amount of such pairs (i, j) that 1<=i<j<=N and A

【bzoj2789】[Poi2012]Letters 树状数组求逆序对

题目描述 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. 输入 第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度. 第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母. 输出 一个非负整数,表示最少的交换次数. 样例输入 3 ABC BCA 样例输出 2 题解 树状数组求逆序对 一个结论:将序列A通过交换相邻元素变换为序列B,需要的最小次数为A中

蓝桥杯小朋友排队(树状数组求逆序对)

居然存在身高为0的数据... 树状数组求逆序对原理: add(h[j],1); //将身高为h[j]的数据的出现次数加1 sum(h[j]);//求i<j 且 h[i] <=h[j] 的数据出现次数之和  那么 i-sum(h[j]) 为 i > j 且 h[i] > h[j] 数据的出现次数之和 即为 逆序对数 #include"cstdio" #include"cstring" #define lowbit(i) i&(-i) u

HDU 1394 树状数组求逆序对

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13036    Accepted Submission(s): 7968 Problem Description The inversion number of a given number sequence a1, a2, ..., an

HDU 1394 Minimum Inversion Number (树状数组求逆序对)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题目让你求一个数组,这个数组可以不断把最前面的元素移到最后,让你求其中某个数组中的逆序对最小是多少. 一开始就求原来初始数组的逆序对,树状数组求或者归并方法求(可以看<挑战程序设计>P178),然后根据最前面的元素大小递推一下每次移到最后得到的逆序数,取最小值. 1 #include <iostream> 2 #include <cstdio> 3 #include

poj3067Japan——树状数组查找逆序对

题目:http://poj.org/problem?id=3067 利用树状数组查找逆序对. 代码如下: #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int t,n,m,k; long long f[1005],ans; struct N{ long long aa,bb; }edge[1000005]; bool