歷屆試題 小朋友排隊
時間限制: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 }
法二:
樹狀數組(學習中)。。。