求逆序数

来源:互联网 发布:php旅游网站模板 编辑:程序博客网 时间:2024/06/08 17:51

题目描述

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

输入输出格式

输入格式:

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

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

输出格式:

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

输入输出样例

输入样例#1:
65 4 2 6 3 1
输出样例#1:
11

说明

对于50%的数据,n≤2500

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





【题解】

核心思路就是树状数组+离散化


#include<cstdio>#include<algorithm>using namespace std;const int maxn=40010;int tree[maxn]={0},r[maxn];//r[i]表示第i个输入 在所有输入从大到小排序后的编号int n;struct Node{int v,site;bool operator<(const Node &x)const{return v<x.v;}}num[maxn];void Update(int i,int value){while(i<=n){tree[i]+=value;i+=i&(-i);}return ;}int sum(int i){int s=0;while(i>0){s+=tree[i];i-=i&(-i);}return s;}int main(){int ans=0;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&num[i].v);num[i].site=i;}sort(num+1,num+n+1);for(int i=1;i<=n;i++)r[num[i].site]=i;//第i个输入是第r[i]大的 /*sum(r[i])求比r[i]小的数的个数(编号j<i) 思路是:从1开始到n循环,每次将第i个输入放入树状数组中。Update(r[i],1)更新比r[i]大的tree.ans+=i-sum(r[i])右边翻译过来就是:所有编号小于i的数个数-所有编号小于i且小于i的数的个数 */for(int i=1;i<=n;i++){Update(r[i],1);ans+=i-sum(r[i]);}printf("%d\n",ans);return 0;}




原创粉丝点击