问题描述
小张在暑假时间来到工地搬砖挣钱。包工头交给他一项艰巨的任务,将一排砖头按照从低到高的顺序排好。可是小张的力量有限,每次只能交换相邻的两块砖头,请问他最少交换几次能够完成任务?
输入
第一行一个整数 n(
1
≤
n
≤
300000
1 \leq n \leq 300000
1≤n≤300000) ,表示砖头数量。
第二行 n 个整数
a
i
(
−
1000000000
≤
a
i
≤
1000000000
a_i(-1000000000 \leq a_i \leq 1000000000
ai(−1000000000≤ai≤1000000000) ,表示砖头的高度。
输出
一行一个整数,表示小张最多可以完成几项任务。
样例数据
输入(1)
5
4 1 3 2 5
输出(1)
4
代码
这个就 归并排序呗
#include <stdio.h>//这是第十二题 变换砖头
long long int bricks[300002];//定义一个数组来存放初始时砖的高度,需要把数组定义在主函数之外。
long long int sorted_bricks[300002];//再定义一个数组来暂时存放排序好的砖,最后再导回到bricks里面
long long count=0;//计数器,来记录有多少个逆序对
void mergesort(long int left,long int right,long long int bricks[],long long int sorted_bricks[])//在这里定义归并排序的函数,略作修改来求逆序对。
{
if(right-left>0)//如果此时的待排序部分不为空,则继续
{
long int middle=(left+right)/2;//首先尽量从中间阶段,进行下一步的归并操作
long int i=left;//保存左边的位置
long int p=left,q=middle+1;//保存中间的位置
mergesort(left,middle,bricks,sorted_bricks);//将此数列再分成两个子数列进行归并
mergesort(middle+1,right,bricks,sorted_bricks);//(这里对了就很奇怪,因为之前用快排的时候也是这样的递归写法,但是排出的结果是错误的)
while(p<=middle||q<=right)//排序的具体操作,两个子数列只要有一个为空,就继续填入,在此之前不断选出较小的来填入
{
if(q>right||(p<=middle&&bricks[p]<=bricks[q]))
sorted_bricks[i++] = bricks[p++];
else
{
sorted_bricks[i++] = bricks[q++];
count=count+middle-p+1;
}
}
for(i = left; i <= right; i++)//将sorted_bricks中排好序的元素复制到bricks中
bricks[i]=sorted_bricks[i];
}
}
int main()
{
long int n;
scanf("%ld",&n);
for(long int i=0;i<n;i++)
{
scanf("%lld",&bricks[i]);
}//存放砖的状态
//本题的思路是用归并排序求逆序对
mergesort(0,n-1,bricks,sorted_bricks);//这里和讨论区里给出的归并算法不一样的是,C语言中需要把数组作为参数传入函数中。
printf("%ld\n",count);
return 0;
}