题目意思
现在有一个n个数值的无序序列,现在要求这个序列中的逆序对个数,并且每个逆序对需要支付x元。但是那你可以耍一个小把戏就是支付y元将这个序列中相邻的两个数值交换。现在问你你需要的最小支付是多少元。
解题思路
题目意思就是问你一个序列中有多少个逆序对。我们如果支付y元将两个相邻的数值进行交换,那么就消除了一个逆序对,和直接算逆序对的个数是相同的意思。那么问题就在于怎样才能有最小的花费。如果逆序对支付的少,那么我们就直接求逆序对个数乘上每个逆序对需要支付的钱。同理如果交换数值花费的少,那么我们就将序列中所有的逆序对都用交换来消除,这样得到的花费就是交换的花费乘上逆序对个数。
要求逆序对的个数我们就用到了归并排序算法,用归并算法去求一个序列中的逆序对个数。
代码部分
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int n,x,y;
int a[maxn],b[maxn];
inline ll merge(int l, int mid, int r)///合并函数
{
int i, j, k;
i = l;
j = mid + 1; ///避免重复比较a[mid]
k = 0;
ll ans=0;
while (i <= mid && j <= r) ///把两个数组从第一个开始比较小的加入整理数组直到一个数组都加入
{
if (a[i] > a[j])
{
ans+=(mid-i+1);
b[k++] = a[j++];
}
else
b[k++] = a[i++];
}
while (i <= mid) ///将剩下的的全部加入整理后的数组
b[k++] = a[i++];
while (j <= r)
b[k++] = a[j++];
for (i = 0; i < k; i++) ///把整理后的数组替代掉之前的未整理的
a[l + i] = b[i]; ///注意,应从a[l+i]开始赋值
return ans;
}
inline ll merge_sort( int l, int r)
{
ll ans=0;
if (l < r) ///细分到每一个元素都为一个数组后开始合并
{
int mid = (l + r)>>1;
ans += merge_sort(l,mid); ///对左边进行排序
ans += merge_sort(mid+1,r); ///对右边进行排序
ans += merge(l, mid, r); ///把排序好的数据合并
}
return ans;
}
int main()
{
while(scanf("%d%d%d",&n,&x,&y)!=EOF)
{
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
ll ans = merge_sort(1,n);
ll temp=0;
if(x>y)
{
temp=ans * y;
}
else
{
temp=ans * x;
}
cout<<temp<<endl;
}
return 0;
}