【洛谷P1908】逆序对
题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
输入输出格式
输入格式:
第一行,一个数n,表示序列中有n个数。
第二行n个数,表示给定的序列。
输出格式:
给定序列中逆序对的数目。
输入输出样例
说明
对于50%的数据,n≤2500
对于100%的数据,n≤40000。
题解:
这应该算是树状数组入门的经典题了。
普及组的做法这就是归并的思想(就是在归并排序里加一句话,仅此而已)
那么今儿个我们来用用树状数组。
逆序对就是求一对(si,sj) 满足 i<j 且 si>sj 的对数。
先按大小从大到小sort一遍,
然后只要用树状数组求出第i个数前面位置比i小的个数就可以了,用的是前缀和思想。
注:c[i] 表示的是当前已经插入树状数组中的元素中比 i 小的元素的个数。(重要!!!)
入门题不赘述,代码硬上:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int ans=0,n,c[40005]; 4 struct node{ 5 int val,pos; 6 }a[40005]; 7 bool cmp(node a,node b) 8 { 9 return a.val>b.val; 10 } 11 void update(int x) 12 { 13 for (int i=x; i<=n; i+=i&(-i)) 14 c[i]++; 15 } 16 int get(int x) 17 { 18 int cnt=0; 19 for (int i=x; i>0; i-=i&(-i)) 20 cnt+=c[i]; 21 return cnt; 22 } 23 int main() 24 { 25 scanf("%d",&n); 26 for (int i=1; i<=n; i++) 27 { 28 scanf("%d",&a[i].val); 29 a[i].pos=i; 30 } 31 sort(a+1,a+1+n,cmp); 32 for (int i=1; i<=n; i++) 33 { 34 update(a[i].pos); 35 ans+=get(a[i].pos-1); 36 } 37 cout<<ans<<endl; 38 return 0; 39 }
加油加油加油!!!fighting fighting fighting !!!