最小交换
时间限制:1 sec
空间限制:256 MB
问题描述
给定一个 1 到 n 的排列(即一个序列,其中 [1,n] 之间的正整数每个都出现了恰好 1 次)。
你可以花 1 元钱交换两个相邻的数。
现在,你希望把它们升序排序。求你完成这个目标最少需要花费多少元钱。
输入格式
第一行一个整数 n,表示排列长度。
接下来一行 n 个用空格隔开的正整数,描述这个排列。
输出格式
输出一行一个非负整数,表示完成目标最少需要花多少元钱。
样例输入
3
3 2 1
样例输出
3
样例解释
你可以:
花 1 元交换 1,2,序列变成 3 1 2。
花 1 元交换 1,3,序列变成 1 3 2。
花 1 元交换 2,3,序列变成 1 2 3。
总共需要花 3 元。
可以证明不存在更优的解。
数据范围
对于 20% 的数据,保证 n<=7。
对于 60% 的数据,保证 n<=1,000。
对于 100% 的数据,保证 n<=200,000。
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int ans = 0;//计数
vector<int> line;//各个元素
vector<int> NewLine;//存储新排列好的序列
int merger(int l,int r){
if(l >= r) //l == r --> 一个元素 无法归并
return 0;
int mid = r >> 1;//向左移1位 即利用二进制的性质 二分
merger(l,mid);//归并前驱序列
merger(mid + 1,r);//归并后驱序列
int q = l,p = mid + 1;
//p > r代表右半部分已经归并完成
//q <= mid && line[q] < line[p] -> 前驱序列的元素更小
if(p > r || q <= mid && line[q] < line[p])
NewLine.push_back(line[q++]);//q++ ->将q移到下一位
else{
NewLine.push_back(line[p++]);
ans += mid - q + 1;//参考冒泡排序(已证明最少的交换次数即冒泡交换次数)
}
return ans;//返回交换次数
}
int getAnswer(int n){
int l = 0,r = n - 1;
return merger(l,r);
}
int main(int argc, char const *argv[]) {
//n 代表元素数目
int n;
scanf("%d",&n);
for(int i = 0;i < n;i++){
int a;
scanf("%d",&a);
line.push_back(a);
}
printf("%d",getAnswer(n));
return 0;
}