您的位置:首页 > 理论基础 > 数据结构算法

HDU - 2838 Cow Sorting解题报告(树状数组求逆序数相关+技巧)

2017-04-24 21:00 411 查看

题目大意:

有很多的牛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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息