HDU - 6318 - Swaps and Inversions
题意:
可以花费 x 或 y 交换相邻的两个元素
求将数列中所有的逆序对消除需要的最少花费
选xy中小的作为花费,消除所有的逆序对就是将序列排序,需要的交换次数就是逆序对数
最后答案就是 逆序对数 * min (x, y)
可以用树状数组+离散化 或 归并排序来求出逆序对数(因为数的范围较大,所以在树状数组中要离散化)
// 树状数组 + 离散化
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1e5 + 10;
int n, x, y, sz;
int a[maxn], Rank[maxn], sum[maxn];
void add(int x){
for(; x<=n; x += (x&-x)) sum[x] ++;
}
int Sum(int x){
int ans = 0;
for(; x>0; x -= (x&-x)) ans += sum[x];
return ans;
}
int main()
{
while(scanf("%d%d%d", &n, &x, &y) != EOF){
sz = 0;
memset(sum, 0, sizeof sum);
for(int i=1;i<=n;i++){
scanf("%d", &a[i]);
Rank[i] = a[i];
}
sort(Rank+1, Rank+1+n);
sz = unique(Rank+1, Rank+1+n) - Rank - 1;
long long ans = 0;
for(int i=1;i<=n;i++){
int num = lower_bound(Rank+1, Rank+1+sz, a[i]) - Rank;
add(num);
ans += i - Sum(num);
}
if(x < y) ans = ans * x;
else ans = ans * y;
printf("%lld\n", ans);
}
return 0;
}
// 归并排序
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 1e5 + 10;
int n, x, y;
long long ans;
int a[maxn], b[maxn];
void Merge(int l, int mid, int r){
int p1 = l, p2 = mid + 1;
int sz = 0;
while(p1 <= mid && p2 <= r){
if(a[p1]>a[p2]) ans += mid - p1 + 1, b[++sz] = a[p2++];
else b[++sz] = a[p1++];
}
while(p1 <= mid) b[++sz] = a[p1++];
while(p2 <= r) b[++sz] = a[p2++];
for(int i=1;i<=sz;i++) a[l+i-1] = b[i];
}
void merge_sort(int l, int r){
if(l == r) return;
int mid = (l+r) >> 1;
merge_sort(l, mid);
merge_sort(mid+1, r);
Merge(l, mid, r);
}
int main()
{
while(scanf("%d%d%d", &n, &x, &y) != EOF){
for(int i=1;i<=n;i++) scanf("%d", &a[i]);
ans = 0;
merge_sort(1, n);
if(x < y) ans = ans * x;
else ans = ans * y;
printf("%lld\n", ans);
}
return 0;
}