Freda的越野跑(openjudge)

来源:互联网 发布:淘宝网店运营教程 编辑:程序博客网 时间:2024/04/27 14:53

Freda的越野跑-openjudge    归并算法求逆序对数

描述

Freda报名参加了学校的越野跑。越野跑共有N人参加,在一条笔直的道路上进行。这N个人在起点处站成一列,相邻两个人之间保持一定的间距。比赛开始后,这N个人同时沿着道路向相同的方向跑去。换句话说,这N个人可以看作x轴上的N个点,在比赛开始后,它们同时向x轴正方向移动。
假设越野跑的距离足够远,这N个人的速度各不相同且保持匀速运动,那么会有多少对参赛者之间发生“赶超”的事件呢?

输入
第一行1个整数N。
第二行为N 个非负整数,按从前到后的顺序给出每个人的跑步速度。
对于50%的数据,2<=N<=1000。
对于100%的数据,2<=N<=100000。
输出
一个整数,表示有多少对参赛者之间发生赶超事件。
样例输入
51 3 10 8 5
样例输出
7
提示
我们把这5个人依次编号为A,B,C,D,E,速度分别为1,3,10,8,5。
在跑步过程中:
B,C,D,E均会超过A,因为他们的速度都比A快;
C,D,E都会超过B,因为他们的速度都比B快;

C,D,E之间不会发生赶超,因为速度快的起跑时就在前边。


解析:

      这道题等价于我们去求整个跑步队列的“顺序对”数目,即先出发的人速度还小的一共有多少对。事实上,这和求逆序对数是一样的方法,只要在输入速度的时候将速度取为相反数就可以实现了。下面我们就按照求逆序对的个数来实现。

      下面来看一下实现的细节。

       整个的思想是利用归并排序有效利用我们已经计算过的、排过序的结果。利用结果的过程体现在merge操作中,假设在二路归并中,下标较小的子数组是a,下标较大的子数组是b,根据归并排序的性质,此时的a和b都已经是有序的了。那么每次如果在a中发现有某个元素a[i]大于b[j],那么我们知道a[i]后面的a中元素都是大于b[j]的,也就必定和b[j]构成逆序对,我们就只需要在最终的统计结果中加上a[i]和a[i]后面元素的总个数。

      下面来看代码:

#include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N = 100010;long ans = 0;       //最后记录一共有多少逆序对,注意一共至多10^5个人,所以用longint speed[N];       //输入的速度int tmp[N];         //merge中的辅助数组void merge(int left, int right, int middle) {for (int i = left; i <= right; i++)tmp[i] = speed[i];int index1, index2;index1 = left; index2 = middle + 1;int loc = left;while (index1 <= middle && index2 <= right) {if (tmp[index1] <= tmp[index2])speed[loc++] = tmp[index1++];else {ans += (middle - index1 + 1);  //更新answerspeed[loc++] = tmp[index2++];}}while (index1 <= middle)speed[loc++] = tmp[index1++];while (index2 <= right)speed[loc++] = tmp[index2++];}void mergesort(int left, int right) {int middle;if (left < right) {middle = (left + right) / 2;mergesort(left, middle);mergesort(middle + 1, right);merge(left, right, middle);}}int main(){int n; cin >> n;for (int i = 0; i <n; i++) {scanf("%d", &speed[i]);speed[i] = -speed[i];    //将求顺序对转化为求逆序对}mergesort(0, n - 1);cout << ans << endl;return 0;}

that's all!

原创粉丝点击