题目大意
若干头牛,每头牛有一个权值,通过相邻交换将牛按权值升序排列,每次交换以两头牛的权值之和为代价,求最小代价。
思路
原排列确定后,每个数的与其之前的数形成的逆序对是固定的,(此类最小交换次数问题考虑逆序数)每次仅考虑一个数之前与其形成的逆序对避免重复计算,每次通过树状数组计算一次逆序对数(a)和次数前与其形成逆序的数之和(s),维护两个树状数组,没次代价为x * a + s
若干头牛,每头牛有一个权值,通过相邻交换将牛按权值升序排列,每次交换以两头牛的权值之和为代价,求最小代价。
思路
原排列确定后,每个数的与其之前的数形成的逆序对是固定的,(此类最小交换次数问题考虑逆序数)每次仅考虑一个数之前与其形成的逆序对避免重复计算,每次通过树状数组计算一次逆序对数(a)和次数前与其形成逆序的数之和(s),维护两个树状数组,没次代价为x * a + s
#include <iostream>
#include <cstdio>
#include <string.h>
#define MAXN 100010
using namespace std;
int a[MAXN], n, upper = 0;
long long sum[2][MAXN];
int lowbit(int x)
{
return x & (-x);
}
void update(int num, int i, int val)
{
while (i <= upper)
{
sum[num][i] += val;
i += lowbit(i);
}
}
long long getSum(int num, int i)
{
long long s = 0;
while (i > 0)
{
s += sum[num][i];
i -= lowbit(i);
}
return s;
}
int main()
{
//freopen("aa.txt", "r", stdin);
long long result = 0, tol = 0;
memset(sum, 0, sizeof(sum));
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
if (a[i] > upper)
upper = a[i];
}
for (int i = 1; i <= n; i++)
{
long long temp = getSum(0, a[i]);
long long temp1 = getSum(1, a[i]);
result += (long long)(a[i] * (i - 1 - temp) + tol - temp1);
tol += a[i];
update(1, a[i], a[i]);
update(0, a[i], 1);
}
cout << result << endl;
}