Hdu 2838 step5.3.7 (树状数组)

Hdu 2838 step5.3.7

Cow Sorting

 

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 2081    Accepted Submission(s): 642

 

 

Problem Description

Sherlock's N (1 ≤ N ≤ 100,000) cows are lined up to be milked in the evening. Each cowhas a unique "grumpiness" level in the range 1...100,000. Sincegrumpy cows are more likely to damage Sherlock's milking equipment, Sherlockwould like to reorder the cows in line so they are lined up in increasing orderof grumpiness. During this process, the places of any two cows (necessarilyadjacent) can be interchanged. Since grumpy cows are harder to move, it takesSherlock a total of X + Y units of time to exchange two cows whose grumpinesslevels are X and Y.

 

Please help Sherlock calculate the minimaltime required to reorder the cows.

 

 

Input

Line 1: A single integer: N

Lines 2..N + 1: Each line contains a singleinteger: line i + 1 describes the grumpiness of cow i.

 

 

Output

Line 1: A single line with the minimal timerequired to reorder the cows in increasing order of grumpiness.

 

 

Sample Input

3

2

3

1

 

 

Sample Output

7

 

Hint

 

Input Details

 

Three cows are standing in line withrespective grumpiness levels 2, 3, and 1.

Output Details

 

2 3 1 : Initial order.

2 1 3 : After interchanging cows withgrumpiness 3 and 1 (time=1+3=4).

1 2 3 : After interchanging cows withgrumpiness 1 and 2 (time=2+1=3).

 

 

 

Source

2009 Multi-University Training Contest 3 -Host by WHU

题解:

这道题用的是树状数组,因为是算相邻牛交换,然后达到不递减的效果,每次的代价是两只牛的暴力值相加,。根据题意,可知我们要算的是,在当前牛cows前面有多少暴力值比它大的牛。交换当前牛的代价是到当前牛的总暴力值ssum,减去顺序暴力值的总和sum,在加上逆序暴力牛的只数*当前牛的暴力值(len2-len1)*cows。即ans += ssum – sum + (len2-len1)*cows。而计算sum的值就可以用树状数组——将当前牛的暴力值加入到树状数组中add(cows,cows),不排除有相等的暴力值,所以要记录重复暴力值的个数,用dc[cows]记录,而计算到当前这个暴力值,比它小的牛的暴力值的总和,用getsum(cows),然后计算出有多少个比当前牛小或者相等的值,len2 += dc[x];因为这道题的值是比较大的,所以要用__int64,而且最后在计算ans的时候所有的值都要转换为__int64来计算,不然会出错。

源代码:

#include <iostream>

#include <stdio.h>

#include <algorithm>

using namespace std;

#define MAX 100050

int cows,len1,len2;

__int64 c[100050];

int dc[100050];

 

int lowbit(int x)

{

   returnx&(-x);

}

 

void add(int x,int num)

{

   while(x> 0 && x < MAX)

   {

     c[x] += num;

     dc[x]++;

     x += lowbit(x);

   }

}

 

__int64 getsum(int x)

{

   __int64sum = 0;

   while(x> 0 && x < MAX)

   {

     sum += c[x];

     len2 += dc[x];

     x -= lowbit(x);

   }

   returnsum;

}

 

int main()

{

   intn;

   __int64ans,ssum,sum;

   while(scanf("%d",&n)!=EOF)

   {

     ans = 0;

     ssum = 0;

     memset(c,0,sizeof(c));

     memset(dc,0,sizeof(dc));

     for(int i = 0;i < n;i++)

     {

        scanf("%d",&cows);

        add(cows,cows);

        ssum += (__int64)cows;

        len1 = i+1;

        len2 = 0;

        sum = getsum(cows);

        ans += ssum - sum +(len1-len2)*(__int64)cows;

     }

     printf("%I64d\n",ans);

   }

   return0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值