hdu 2838 树状数组求逆序数及交换位置产生移动的数的和

Cow Sorting

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1600    Accepted Submission(s): 507


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.
 

Input
Line 1: A single integer: N
Lines 2..N + 1: Each line contains a single integer: line i + 1 describes the grumpiness of cow i.
 

Output
Line 1: A single line with the minimal time required 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 with respective grumpiness levels 2, 3, and 1. Output Details 2 3 1 : Initial order. 2 1 3 : After interchanging cows with grumpiness 3 and 1 (time=1+3=4). 1 2 3 : After interchanging cows with grumpiness 1 and 2 (time=2+1=3).
 

Source
 
  题意:给你N个排列不规则的数,任务是把它从小到大排好,每次只能交换相邻两个数,交换一次的代价为两数之和,求最小代价

注意    每次交换 都必须只能交换相邻的2个 

思路:对于当前数X,我们如果知道前面比它大的数有多少,假设为K,那么有部分代价是确定的,那就是K*X;然后还得加上比它大的那些数之和,这就是当数列到X为止,排好所需要的最小代价。

注意本题不能用long  long  必须用__int64  坑!

#include<stdio.h>
#include<string.h>
#define ll __int64
ll c[100000+5],v[100000+5];
int n;
int Lowbit(int k)
{
    return (k&-k);
}
void update(int pos,int num,int val)
{
    while(pos<=n)
    {
        c[pos]+=num;
        v[pos]+=val;
        pos+=Lowbit(pos);
    }
}
ll sum_count(int pos)
{
    ll  s=0;

    while(pos>0)
    {
        s+=c[pos];
        pos-=Lowbit(pos);
    }
    return s;
}
ll sum(int pos)
{
    ll s=0;

    while(pos>0)
    {
        s+=v[pos];
        pos-=Lowbit(pos);
    }
    return s;
}
int main()
{
    int i,x;
    while(scanf("%d",&n)!=-1)
    {
        memset(c,0,sizeof(c));
        memset(v,0,sizeof(v));
        ll ans=0,k2,k1;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&x);
            update(x,1,x);
            k1=i-sum_count(x);///到此为止  比x大的个数;
///sum_count[x] 为输入i个数的时候 x之前有sum_count[x]个比x小的数 用i相减则为大于x的个数
            if(k1!=0)
            {
            k2=sum(n)-sum(x);///到此为止  比x大的数的和;
            ans+=x*k1+k2;///到此为止 比x大的数与x交换之后的和;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


 

 

参考  http://blog.csdn.net/me4546/article/details/6333225
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值