题意:就是求将之前的排列变成一个递增的排列,每交换两个数的代价为两个数的和,求变成递增的排列所需的最小代价为多少。
本题相当于冒泡排序,对于冒泡排序,每个点的贡献价值的次数等于前面大于它的数的个数加上后面小于它的个数。
分析:其实这个结果和逆序数有关,对某个位置i,如果前面比他大的有x个,那么a[i]至少要加x次
如果后面有y个比a[i]小,那么a[i]至少要加y次,也就是说用两个树状数组来分别维护当前位置时前面有多少比他大,后面有多少个比他小
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define N 100001 #define ll long long ll C[N],B[N]; ll num[N]; int T; int Lowbit(int x){ return x&(x^(x-1)); } void add(ll C[],ll pos,ll num) { while(pos <= N) {//x最大是N C[pos] += num; pos += Lowbit(pos); } } ll Sum(ll C[],ll end) { ll sum = 0; while(end > 0) { sum += C[end]; end -= Lowbit(end); } return sum; } int main() { int s, t, i, j, T; ll ans; while(~scanf("%d",&T)) { memset(C,0,sizeof(C)); memset(B,0,sizeof(B)); memset(num,0,sizeof(num)); ans = 0; for(i = 1; i <= T; i ++) { scanf("%I64d",&num[i]); add(C,num[i],1); ans += num[i] *(i - Sum(C,num[i])) ;//计算当前点前面大于它的数的个数 } for(i = T; i > 0; --i){//注意是从T至0的, ans += num[i] * Sum(B,num[i] - 1);//计算当前点后面小于它的个数 add(B,num[i],1);//从后面算起,然后加起来,那么Sum求出来的就是它后面小于它的个数了 } printf("%I64d\n",ans); } return 0; }