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.
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.
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
7HintInput 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;
}