HDU 2838 Cow Sorting(树状数组)

HDU 2838 Cow Sorting(树状数组)

Problem Description
Sherlock's N (1 ≤ N ≤ 100,000) cows are lined up to be milked in the evening. Each cow has a unique "grumpiness" level in the range 1...100,000. Since grumpy cows are more likely to damage Sherlock's milking equipment, Sherlock would like to reorder the cows in line so they are lined up in increasing order of grumpiness. During this process, the places of any two cows (necessarily adjacent) can be interchanged. Since grumpy cows are harder to move, it takes Sherlock a total of X + Y units of time to exchange two cows whose grumpiness levels are X and Y.

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>


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值