HDU 2838 Cow Sorting(树状数组)
Please help Sherlock calculate the minimal time required to reorder the cows.
分析:
首先每次只能交换相邻的两头牛,并且最后要求升序排列,所以最后整个序列的逆序是0,每次交换只可以消除1个逆序。(令a[i]的逆序是从1到i-1比它大的数的个数。)
现在想问我们用插入排序的方式从左到右一个一个消除逆序的话,最后得到的时间和是最小的吗?是的。证明如下:
对于每个原始的a[i],假设在它前面有x和y比a[i]大,所以a[i]的逆序是2,消除a[i]逆序的代价必须是x+y+2a[i],因为如果x或y不与a[i]交换,那么x或y就永远在a[i]前面,逆序不可能消除。所以要消除任意a[i]的逆序,以上代价都是必须的且是最小的。
现在用树状数组来求消除逆序的代价。要建两颗树状数组,其中树组1用来计算当前已经有多少个值比a[i]大已经出现了,即temp1(类似于上面例子的2=temp1),树组2用来计算当前所有比a[i]大的值之和是多少?即temp2(x+y=temp2)。
从左到右依次扫描a[i],首先执行temp1=sum(1,MAXN)-sum(1,a[i]); temp2=sum(2,MAXN)-sum(2,a[i]);则temp1*a[i]+temp2就是消除a[i]逆序的代价,所以ans+=temp1*a[i]+temp2;
然后接着插入a[i],执行:
add(1,a[i],1); add(2,a[i],a[i]);
最终结果可能超出int,要用long long
AC代码:31ms
<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=100000+100;
long long c[3][MAXN];
int lowbit(int x)
{
return x&(-x);
}
long long sum(int i,int x)
{
long long res=0;
while(x>0)
{
res +=c[i][x];
x-=lowbit(x);
}
return res;
}
void add(int i,int x,long long v)
{
while(x<MAXN)
{
c[i][x]+=v;
x+=lowbit(x);
}
}
int main()
{
int n;
while(scanf("%d",&n)==1&&n)
{
memset(c,0,sizeof(c));
long long ans=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
long long temp1=sum(1,MAXN)-sum(1,x);
long long temp2=sum(2,MAXN)-sum(2,x);
ans += temp1*x+temp2;
add(1,x,1);
add(2,x,x);
}
printf("%I64d\n",ans);
}
return 0;
}
</span>