题目大意:
有很多的牛n(100,000),每个牛都有一个暴躁值,现在想把这些牛按照暴躁值从小到大排序,每次只能交换两头相邻的牛,交换他们付出的代价就是,两头牛暴躁值的和。现在问你把这些牛按照暴躁值从小到大排序至少需要付出多少代价。
分析:
有点像求哪个逆序数,但是这里要分析一个问题,需要调换的次数是一定的,那么,如何调换才能付出最小的的代价。
比较感性的想法就是,每次调换代价最小的,但是这个贪心策略确实是有一点牵强,我就不证明了,应该是不对的,而且每次查找最小的也是够费劲的。
想简单一点,能不能证明出来,付出的代价是一定的。假设:存在 a [ i ] > a [ j ] ( i < j ) 。那么,在若干次相邻元素调换的过程中,一定存在一次操作是,调换 a [ i ] 和 a [ j ] (这里的 i,j 已经不是原来的 i,j 了,但是, a [ i ] 和 a [ j ] 还是原来的值,只是现在他们的位置通过之前的若干次调换,变成了相邻的)。所以,每一个逆序数对就意味着这两个要进行一次调换,也就是要付出一次代价,所以付出的代价确实是一定的。
关于代码实现,用两个树状数组。tree [ i ] 数组表示比 i 小的数的总和,treenum [ i ]数组表示比 i 小的数的个数。然后如何找到比 i 大的,就是 tree [ maxn ] - tree [ i ],treenum [ maxn ] - treenum [ i ]。
代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
long long int tree[105000]={0};
long long int treenum[105000]={0};
int n;
long long int s=0;
int lowbit(int x)
{
return x&(-x);
}
void add(int x)//tree[x]及以上都加x
{
int t=x;
while(x<=100000)
{
treenum[x]+=1;
tree[x]+=t;
x=x+lowbit(x);
}
}
long long int sum(int x)
{
long long int f=0;
while(x>=1)
{
f+=tree[x];
x=x-lowbit(x);
}
return f;
}
long long int sumnum(int x)
{
long long int f=0;
while(x>=1)
{
f+=treenum[x];
x=x-lowbit(x);
}
return f;
}
int main()
{
int x;
cin>>n;
memset(tree,0,sizeof(tree));
memset(treenum,0,sizeof(treenum));
s=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
//cout<<sum(100000)<<endl<<sum(x)<<endl;
s=s+(sum(100000)-sum(x))+(sumnum(100000)-sumnum(x))*x;
add(x);
}
cout<<s<<endl;
}