Hdu 2838 Cow Sorting 树状数组

Cow Sorting

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


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).
 
题意:有很多牛,每头牛一个编号,从1到n,然后它们打乱了顺序,要求把它们从小到到大排序,排序过程只能相邻的两头牛调换位置,花费为两头牛的编号之和。
思路:
输入的编号a,只要找前面有多少数比它大,比它大的数记为k1,再把比它大的数的值加起来为k2,则这只牛的花费为a * k1 + k2。用sumA 存比下标小的数的值之和 用sumN 存比下标的数小的数的个数和
#include<stdio.h>
#include<string.h>
#define ll __int64
ll sumN[100005],sumA[100005];
int n; 
void update(int pos,int N,int A){
	while(pos <= n){
		sumN[pos] += N;	 //每个比自己大的数所存的比自己小的数的个数的值加一 
		sumA[pos] += A;	 // 每个比自己大的数所存的比自己小的数的值的和数 加该数的值 
		pos += pos & -pos;
	}
}
ll getSumN(int pos){ //得到的是比a小的数的个数 
	ll sum = 0;
	while(pos > 0){
		sum += sumN[pos];	//sumN存的是比自己小的数的个数 
		pos -= pos & -pos;
	}
	return sum;
}
ll getSumA(int pos){ //得到比a小的数的数值之和 
	ll sum = 0;
	while(pos > 0){
		sum += sumA[pos];	//sumA存的是比自己小的数的数值和 
		pos -= pos & -pos;
	}
	return sum;
}
int main(){
	ll a,k1,k2;
	while(scanf("%d",&n) != EOF){
		ll ans = 0;
		memset(sumN,0,sizeof(sumN));
		memset(sumA,0,sizeof(sumA));
		for(int i = 1;i <= n;i++){
			scanf("%d",&a);
			update(a,1,a); 		//把输入的数扔进去,比它小的数就可以把记录比自己大的数的个数加一。 
			k1 = i - getSumN(a);//i为总数 减去 比自己小的数的个数之和 得到比a大的数个数之和 
			if(k1 != 0){
				k2 = getSumA(n) - getSumA(a); //get(n)为所有数的和 减去比自己小的数的值的和 得到比a大的数的数值之和 
				ans += a * k1 + k2;
			}
		}
		printf("%I64d\n",ans);
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值