HDU - 6318 - Swaps and Inversions(逆序对数)

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;
}

猜你喜欢

转载自blog.csdn.net/w326159487/article/details/81227143