作者:tanhuixi135_414 | 来源:互联网 | 2023-10-14 16:23
问题描述
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。
该问题的解法有两种
一:归并排序
归并排序的特点非常符合本题,本题要求只能相邻的元素相互交换,而归并排序本质排序也是这样;具体怎么解,看下边的代码,本人小白一个,参加了这次的java蓝桥杯,遇到这个题后,不知道如何解答,在网上搜到的大多是c/c++,搜到的java写的也大多有错误,写了好久总是不对,还以为本题无法用java写出,终于写出来了 哈哈 功夫不负有心人,注释中的数组都是值得对象数组,元素也是对象元素;
二:树状数组(不太了解这块,所以不说了)
import java.util.*;public class Main {
/**
* @param args
*/
public static class num //内部类
{
public long h;//用long,否则会出错
public long t;//用long,否则会出错
}
static num num1[]=new num[100001];//一开始开了100005个,但是造成了有一组测试数据超时
static num num2[]=new num[100001];//
public static void main(String[] args) {
for(int i=0;i<100001;i++)//对内部类对象初始化
{
num1[i]=new num();
num2[i]=new num();
}
Scanner input=new Scanner(System.in);
int n=input.nextInt();
for(int j=0;j {
num1[j].h=input.nextInt();
}
merge(num1,0,n-1);
long sum=0;//必须用long,否则会错误
for(int k=0;k {
//System.out.println(num1[k].h+" "+num1[k].t);
sum+=(num1[k].t*(num1[k].t+1))/2;//等差数列求和公示
}
System.out.println(sum);
}
public static void merge(num a[],int left,int right)
{
if(left==right) //终止递归的条件
{
return;
}
int mid=(left+right)/2;
merge(a,left,mid);
merge(a,mid+1,right);
int p=left;
int q=mid+1;
int i=left;
while(p<=mid && q<=right)
{
if(a[p].h>a[q].h)
{
a[q].t+=mid+1-p;//如果左数组第一个元素比右数组第一个元素大,因为左右数组都是从小到大排序的
//所以左数组所有的元素(mid+1-p个)都大于右数组第一个元素;
num2[i++]=a[q++];//注意这里交换的是类对象,这是归并排序的核心知识
}
else
{
a[p].t+=q-1-mid;//左数组的第一个元素小于或者等于右数组的第一个元素,q-1-mid==0,在右数组中,q所指的元素前面的元素就是小于p所指的元素,q-1-mid就是q所指元素的前边元素的个数;
num2[i++]=a[p++];
}
}
while(q<=right)//右数组有剩余,说明左数组的元素都比右数组剩下的元素小
{
num2[i++]=a[q++];
}
q--;//在前边判断循环终止时q=last+1,所以循环终止,所以这里需要减去1
while(p<=mid)
{
a[p].t+=q-mid;
num2[i++]=a[p++];
}
int j=left;
for(;j<=right;j++)
{
a[j]=num2[j];//将排序好的类对象数组传给原类对象数组
}
}
}