OJ链接: 历届试题 小朋友排队
参考博客:蓝桥杯 历届试题 小朋友排队
问题描述
n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。
每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。
如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。
请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
输入格式
输入的第一行包含一个整数n,表示小朋友的个数。
第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。
输出格式
输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
样例输入
3
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。
思路
代码
#include <bits/stdc++.h>
#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 100010
#define MAX 0x06FFFFFF
#define V vector<int>
#define ll long long
using namespace std;
typedef struct Node{
int h,cnt=0;//身高、交换次数(逆序数 )
}Node;
int N;
Node arr[LEN];
Node tmp[LEN];
int ans=0;
void merge(int l,int mid,int r){
int a=l,b=mid+1,//a是arr左区间的循环变量,b是arr右区间的循环变量,
i=0; //i是tmp临时数组的循环变量
while(a<=mid && b<=r) {//左右循环变量均不越界
//左区间的当前元素最小
if(arr[a].h<=arr[b].h){
arr[a].cnt+=b-mid-1;
tmp[i++]=arr[a++];
}else{
arr[b].cnt+=mid-a+1;
tmp[i++]=arr[b++];
}
}
//处理未循环完毕的部分
while(b<=r) tmp[i++]=arr[b++];
b--;
while(a<=mid){
arr[a].cnt+=b-mid;
tmp[i++]=arr[a++];
}
//将临时数组的数据放到工作数组中
for(i=l;i<=r;i++) arr[i]=tmp[i-l];
}
void mergeSort(int l,int r){
if(l<r){
int mid=(l+r)/2;
mergeSort(l,mid);
mergeSort(mid+1,r);
merge(l,mid,r);
}
}
int main(){
// freopen("input4.txt","r",stdin);
I("%d",&N);
int i;
FF(i,N){
I("%d",&arr[i].h);
}
mergeSort(0,N-1);
ll ans=0;
FF(i,N){
ll n=arr[i].cnt;
ans+=(n+1)*n/2;
}
O("%lld",ans);
return 0;
}