历届试题 小朋友排队
时间限制:1.0s 内存限制:256.0MB
问题描述
n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。
每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。
如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。
请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。
如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。
请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
输入格式
输入的第一行包含一个整数n,表示小朋友的个数。
第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。
第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。
输出格式
输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
样例输入
3
3 2 1
3 2 1
样例输出
9
样例说明
首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。
数据规模和约定
对于10%的数据, 1<=n<=10;
对于30%的数据, 1<=n<=1000;
对于50%的数据, 1<=n<=10000;
对于100%的数据,1<=n<=100000,0<=Hi<=1000000。
对于30%的数据, 1<=n<=1000;
对于50%的数据, 1<=n<=10000;
对于100%的数据,1<=n<=100000,0<=Hi<=1000000。
分析:
可以用归并和树状数组做
法一:
归并,具体见代码
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 #define max 100005 5 struct point{ 6 int h; 7 int t;//统计该元素左边比他大的数的个数和该元素右边比他小的数的个数的总和 8 }; 9 point l[max],r[max],c[max]; 10 void Merge(point *a,int first,int last){//归并时,上数组的第一个元素与下数组的第一个元素相等,上数组的指针右移 11 int p,q,temp,mid; 12 mid=(first+last)/2; 13 temp=first; 14 p=first; 15 q=mid+1; 16 while(p<=mid&&q<=last){ 17 if(a[p].h>a[q].h){ 18 a[q].t+=mid+1-p;//上数组的第一个元素比下数组的第一个元素大,下数组的第一个元素前面有mid+1-p个数比他大 19 c[temp++]=a[q++]; 20 } 21 else{ 22 a[p].t+=q-1-mid; 23 //上数组的第一个元素与下数组的第一个元素相等或者上数组的第一个元素比下数组的第一个元素小 24 //注意:上数组的第一个元素与下数组的第一个元素相等时,也就是说下数组的第一个元素的前面的元素都比上数组的第一个元素小 25 //上数组的第一个元素后面有q-1-mid个数比他小 26 c[temp++]=a[p++]; 27 } 28 } 29 while(q<=last){//下数组有剩余 30 c[temp++]=a[q++]; 31 } 32 q--; 33 while(p<=mid){//上数组有剩余,也就是说下数组的所有元素都比上数组剩下的元素小,故上数组每个元素t加q-mid,也就是下数组的元素个数 34 a[p].t+=q-mid; 35 c[temp++]=a[p++]; 36 } 37 int i=first; 38 for(;i<=last;i++){ 39 a[i]=c[i]; 40 } 41 } 42 void MergeSort(point *a,int first,int last){ 43 if(first==last){ 44 return; 45 } 46 int mid=(first+last)/2; 47 MergeSort(a,first,mid); 48 MergeSort(a,mid+1,last); 49 Merge(a,first,last); 50 } 51 int main(){ 52 int n; 53 scanf("%d",&n); 54 //cout<<1<<endl; 55 int i=0; 56 for(;i<n;i++){ 57 scanf("%d",&(l[i].h)); 58 l[i].t=0; 59 } 60 MergeSort(l,0,n-1); 61 long long sum=0;//数的范围 62 for(i=0;i<n;i++){ 63 long long s=l[i].t; 64 //cout<<"h: "<<l[i].h<<" "<<l[i].t<<endl; 65 sum+=(s+1)*s/2;//求和 66 } 67 cout<<sum<<endl; 68 return 0; 69 }
法二:
树状数组(学习中)。。。