题目描述

猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。

输入输出格式

输入格式:

第一行,一个数n,表示序列中有n个数。

第二行n个数,表示给定的序列。

输出格式:

给定序列中逆序对的数目。

输入输出样例

输入样例#1:

6
5 4 2 6 3 1
输出样例#1:

11

说明

对于50%的数据,n≤2500

对于100%的数据,n≤40000。

代码:解法一

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int N,a[],temp[],cnt; void print(){
for(int i=;i<=;i++){
printf("%d ",a[i]);
}
puts("");
} void merge_sort(int l,int r){
if(l>=r) return;
int mid=(l+r)>>;
merge_sort(l,mid);merge_sort(mid+,r); int i=l,j=mid+,point=l;
while(i<=mid&&j<=r){
if(a[i]>a[j]){
temp[point++]=a[j++];
cnt+=(mid-i+);
}
else{
temp[point++]=a[i++];
}
} while(i<=mid) temp[point++]=a[i++];
while(j<=r) temp[point++]=a[j++]; for(int k=l;k<=r;++k)
a[k]=temp[k];
// print();
} int main(){
// freopen("01.txt","r",stdin); scanf("%d",&N);
for(int i=;i<=N;++i)
scanf("%d",&a[i]); merge_sort(,N); printf("%d\n",cnt);
return ;
}

暴力枚举的话,可以过两个点~

转载题解如下:http://blog.csdn.net/acdreamers/article/details/16849761

归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来。

在合并的过程中(设l<=i<=mid,mid+1<=j<=h),当a[i]<=a[j]时,并不产生逆序数;当a[i]>a[j]时,在

前半部分中比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话,逆序数要加上mid+1-i。因此,可以在归并

排序中的合并过程中计算逆序数.

解法二:树状数组+离散化

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std; const int N = ; struct Node
{
int val;
int pos;
}; Node node[N];
int c[N], reflect[N], n; bool cmp(const Node& a, const Node& b)
{
return a.val < b.val;
} int lowbit(int x)
{
return x & (-x);
} void update(int x)
{
while (x <= n)
{
c[x] += ;
x += lowbit(x);
}
} int getsum(int x)
{
int sum = ;
while (x > )
{
sum += c[x];
x -= lowbit(x);
}
return sum;
} int main()
{
while (scanf("%d", &n) != EOF && n)
{
for (int i = ; i <= n; ++i)
{
scanf("%d", &node[i].val);
node[i].pos = i;
}
sort(node + , node + n + , cmp); //排序
for (int i = ; i <= n; ++i) reflect[node[i].pos] = i; //离散化
for (int i = ; i <= n; ++i) c[i] = ; //初始化树状数组
long long ans = ;
for (int i = ; i <= n; ++i)
{
update(reflect[i]);
ans += i - getsum(reflect[i]);
}
printf("%lld\n", ans);
}
return ;
}

转载自http://blog.csdn.net/alongela/article/details/8142965

给定n个数,要求这些数构成的逆序对的个数。除了用归并排序来求逆序对个数,还可以使用树状数组来求解。

树状数组求解的思路:开一个能大小为这些数的最大值的树状数组,并全部置0。从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了。把所有的加起来就是总的逆序对数。

题目中的数都是独一无二的,这些数最大值不超过999999999,但n最大只是500000。如果采用上面的思想,必然会导致空间的巨大浪费,而且由于内存的限制,我们也不可能开辟这么大的数组。因此可以采用一种称为“离散化”的方式,把原始的数映射为1-n一共n个数,这样就只需要500000个int类型的空间。

离散化的方式:

struct Node

{

int val;

int pos;

};

Node node[500005];

int reflect[500005];

val存放原数组的元素,pos存放原始位置,即node[i].pos = i。

把这些结构体按照val的大小排序。

reflect数组存放离散化后的值,即reflect[node[i].pos] = i。

这样从头到尾读入reflect数组中的元素,即可以保持原来的大小关系,又可以节省大部分空间。

这个可以辅助理解

http://blog.csdn.net/cattycat/article/details/5640838

树状数组实际上还是一个数组,只不过它的每个元素保存了跟原来数组的一些元素相关的结合值。

若A为原数组,定义数组C为树状数组。C数组中元素C[ i ]表示A[ i –lowbit( i ) + 1]至A[ i ]的结合值。

lowbit(i)是i的二进制中最后一个不为零的位数的2次方,可以这样计算

lowbit(i)=x&(-x)

lowbit(i)=x&(x^(x-1))

洛谷 P1908 逆序对 Label:归并排序||树状数组 不懂的更多相关文章

  1. 洛谷P1908 逆序对(线段树解法)

    题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定 ...

  2. [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)

    [NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...

  3. BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组

    BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一 ...

  4. 洛谷 P1908 逆序对(归并排序解法)

    树状数组解法:https://www.cnblogs.com/lipeiyi520/p/10846927.html 题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不 ...

  5. 洛谷 P1908 逆序对(树状数组解法)

    归并排序解法:https://www.cnblogs.com/lipeiyi520/p/10356882.html 题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不 ...

  6. 洛谷P1908 逆序对 [权值线段树]

    题目传送门 逆序对 题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的 ...

  7. 洛谷P1908 逆序对 (树状数组+离散化)

    模板题,树状数组加上离散化求逆序对. 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 ...

  8. 洛谷P1908 逆序对

    P1908 逆序对 2.2K通过 4.4K提交 题目提供者该用户不存在 标签云端 难度普及/提高- 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 归并排序党注意了!数组要开… ...

  9. 洛谷 P1908 逆序对

    \[传送门qwq\] 题目描述 猫猫\(TOM\)和小老鼠\(JERRY\)最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计. 最近,\(TOM\)老猫查阅 ...

随机推荐

  1. html 构建响应式网站之viewport的使用

    在网页代码的头部,加入一行viewport元标签 <!DOCTYPE html> <html lang="en"> <head> <met ...

  2. HDOJ 2088

    #include<cstdio> int main() { ],i,j,n,x,k=; int sum,ans; while(scanf("%d",&n)!=E ...

  3. backbone杂记

    国人的一个不错的分享:http://gavin.iteye.com/blog/1446277 backbone项目如何组织文件结构 引用: http://bocoup.com/weblog/organ ...

  4. Continuous Subarray Sum

    Given an integer array, find a continuous subarray where the sum of numbers is the biggest. Your cod ...

  5. Java for LeetCode 188 Best Time to Buy and Sell Stock IV【HARD】

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  6. DFS:Red and Black(POJ 1979)

    红与黑 题目大意:一个人在一个矩形的房子里,可以走黑色区域,不可以走红色区域,从某一个点出发,他最多能走到多少个房间? 不多说,DFS深搜即可,水题 注意一下不要把行和列搞错就好了,我就是那样弄错过一 ...

  7. HDU 1023 Traning Problem (2) 高精度卡特兰数

    Train Problem II Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Sub ...

  8. VS2010设置C++包含目录和库目录

    视图-属性管理器-随便选择一个项目例如MyProject-Debug|Win32-Microsoft.Cpp.Win32.user-右键“属性”-VC++目录 Release同理

  9. 补丁vs错误(codevs 2218 错误答案)

    题目描述 Description 错误就是人们所说的Bug.用户在使用软件时总是希望其错误越少越好,最好是没有错误的.但是推出一个没有错误的软件几乎不可能,所以很多软件公司都在疯狂地发放补丁(有时这种 ...

  10. mybatis 如何查找表里的某一个字段,然后返回它们的结果集list ?

    <select id="findArgByParams" resultType="string" parameterType="map" ...