HDU - 6318 Swaps and Inversions
输入:
n:数组中元素个数
x:最后所存在的每对逆序对所需要花费的钱
y:按任意顺序交换数组中相邻两个元素所要花费的钱
n个数组中元素
输出:求使数组变为升序所需要的最少价格
即求该数组的逆序数(按数组顺序/任意顺序交换次数均为该数组的逆序数次)
归并排序求逆序数:归并排序采用分治策略
ex:
{1,8,3,5,2,4,6,9}
-
{1},{8},{3},{5},{2},{4},{6},{9}
-
{1,8},{3,5},{2,4} ,{6,9}
-
{1,3,5,8},{2,4,6,9}
-
{1,2,3,4,5,6,8,9}
重点在于合并:合并时,假如在中点前(即合并前的左序列)有一个元素arr [i]要大于在中点后(即合并前的右边序列)的一个元素arr[j],那么序数i后面的元素应该都要大于arr[j],逆序数为(m – i+ 1)
/*归并排序求逆序数*/
/*HDU - 6318*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll arr[100005];
ll tmp[100005];
ll ans;
void merge_solve(ll l,ll m,ll r)
{
ll i=l;
ll j=m+1;
ll k=l;
while(i<=m&&j<=r)
{
if(arr[i]>arr[j])
{
tmp[k++]=arr[j++];
/*见合并重点*/
/*把小的先放进修改数组里*/
ans+=m-i+1;
}
else
{
tmp[k++]=arr[i++];
}
}
while(i<=m)
{
tmp[k++]=arr[i++];
/*右序列中数组放完了左序列还没放完的情况*/
}
while(j<=r)
{
tmp[k++]=arr[j++];
/*左序列中数组放完了右序列还没放完的情况*/
}
for(int u=l; u<=r; u++)
arr[u]=tmp[u];
/*把这个区间内修改好的数组放回去*/
}
void merge_sort(ll l,ll r)
{
if(l<r)
{
ll m=(l+r)/2;
merge_sort(l,m);
merge_sort(m+1,r);
merge_solve(l,m,r);
}
}
int main()
{
ll n,x,y;
while(~scanf("%I64d%I64d%I64d",&n,&x,&y))
{
ans=0;
for(ll i=0; i<n; i++)
{
scanf("%I64d",arr+i);
}
merge_sort(0,n-1);
printf("%I64d\n",ans*min(x,y));
}
return 0;
}