小朋友排队(蓝桥杯,acwing,归并)

news2025/1/22 17:51:59

题目描述:

n 个小朋友站成一排。

现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。

每个小朋友都有一个不高兴的程度。

开始的时候,所有小朋友的不高兴程度都是 0。

如果某个小朋友第一次被要求交换,则他的不高兴程度增加 1,如果第二次要求他交换,则他的不高兴程度增加 2(即不高兴程度为 3),依次类推。当要求某个小朋友第 k 次交换时,他的不高兴程度增加 k。

请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。

如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。

输入格式:

输入的第一行包含一个整数 n,表示小朋友的个数。

第二行包含 n 个整数 H1,H2,…,Hn分别表示每个小朋友的身高。

输出格式:

输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。

数据范围:

1≤n≤100000
0≤Hi≤1000000

输入样例:

3
3 2 1

输出样例:

9

样例解释:

首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。

分析步骤:

  第一,看完题目我们可以得知,我们要一个一个将相邻的升高不符合位置的同学移动到正确的位置,并且要移动的次数最少。每个小朋友需要交换的次数是前面比它大的数和后面比它小的数,因为如果前面有比它大的数,那么它必定和前面的交换一次,使得前面大的数排到后面,同理可以知道比它小的数一定要和它交换到前面。这其实是一道求逆序对的题目,所以我们可以用归并排序解决这道题目。
  第二:书写主函数,构建整体框架。
              我们先将升高输入进数组 q 的第一个位置,再将他的第二个值定为 i , 因为 i 为他站的位置,之后进行归并排序从第 0 个 位置到第 n - 1 个位置,进行枚举。解出答案后,因为每次增加的不高兴程度为1 , 2 , 3 ,4.........我们可以轻松看出来这是一个等差数列。所以最终用一个for循环,并且利用等差数列求和公式求出每个小朋友的不高兴程度并且相加,进行动态更新。

int main()
{
    cin>>n;
    for(int i = 0 ; i < n ; i ++){
        cin>>q[i].x;
        q[i].y = i;
    }
    merge(0 , n - 1);
    LL res = 0 ; 
    for(int i = 0 ; i < n ; i ++) res += (LL)sum[i] * (sum[i]+1)/2;
    cout<<res;
    return 0;
}

  第三:书写归并排序

             我们定义的 l , r为我们归并排序的左右边界,所以如果当左边界大于了右边界的话就返回退出。

            求出 mid 将 i 赋值为 l ; j 赋值为 mid+1;看赋值为0;最后再将【l,mid】和【mid+1,r】进行归并排序,直到数字分为一个一个的。大家要始终清楚 i , j , k 代表的是什么,他们所在哪个位置。i左区间第一个数,j为右区间第一个数,k为新数组的第一个位置。这个新数组来存归并后的数据顺序。

            进入while循环注意判断条件只有 i <= mid and j <= r都符合条件时才可以继续循环,如果有一个不满足的话,就代表有一个数组已经全部被排好序了。

            如果左边区间的值 小于等于 右边区间的值的话,也就是前边小朋友的身高 小于 后边小朋友的身高,则这个小朋友需要被调整的次数时 j - mid - 1。为什么是这个值?为表示当前元素q[i]不会产生逆序对。由于q[mid+1...j-1]的元素都大于等于q[i].x,所以与q[i]进行比较的时候,逆序对的数量为j - mid - 1即在右半部分数组中,小于q[i].x的元素的数量。并且将这个值放入我们的新数组temp之中。

           如果左边区间的值 大于 右边区间的值的话,也就是前边小朋友的身高 大于 后边小朋友的身高是,则需要被调整的次数是 mid - i + 1。为什么是这个值?因为表示当前元素q[i]会产生逆序对,逆序对的数量是mid - i + 1,将这个数排到左边数组的最后,即在左半部分数组中,大于q[i].x的元素的数量。并且将这个值放入我们的新数组temp之中。

           倘若这个循环结束了的话,就代表着左边数组或者右边数组有一个已经排完了,这个时候我们就在遍历一下如果左边没有排序完,就进入while循环更新sum值(需要更换的次数);如果右边没有排序完,我们就直接将其放入新数组,不要计算需要更换位置的次数,因为前边的已经排好序了,直接放入进去就行;

           最后将我们刚刚存好的tmp数组的值 ”还给“ 之前的q数组。

void merge(int l, int r)
{
    if(l >= r) return ;
    int mid = (l+r) / 2;
    int i = l , j = mid + 1 , k = 0;
    merge(l , mid) , merge(mid+1 , r);
    while(i <= mid and j <= r){
        if(q[i].x <= q[j].x ){
            sum[q[i].y] += j - mid - 1;
            tmp[k++] = q[i++];
        }
        else{
                sum[q[j].y] += mid - i + 1;
                tmp[k++] = q[j++];
        }
    }
    while(i <= mid){
        sum[q[i].y] += j- mid - 1 ;
        tmp[k++] = q[i++];
    }
    while(j <= r){
        tmp[k++] = q[j++];
    }
    for(int i = l , j = 0 ; i <= r ; j ++ , i ++){
        q[i] = tmp[j];
    }
}

这两个图我给大家标出了i , j ,k的位置,大家可以好好注意注意,对于不理解的位置变化的那个式子,也可以根据这个图自己动手写一些,纸上得来终觉浅,得知此事要躬行

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second
typedef long long LL;

using namespace std;
typedef pair<int, int> PII;

const int N = 1e5+10;
int  n;
PII q[N], tmp[N];
int sum[N];

void merge(int l, int r)
{
    if(l >= r) return ;
    int mid = (l+r) / 2;
    int i = l , j = mid + 1 , k = 0;
    merge(l , mid) , merge(mid+1 , r);
    while(i <= mid and j <= r){
        if(q[i].x <= q[j].x ){
            sum[q[i].y] += j - mid - 1;
            tmp[k++] = q[i++];
        }
        else{
                sum[q[j].y] += mid - i + 1;
                tmp[k++] = q[j++];
        }
    }
    while(i <= mid){
        sum[q[i].y] += j- mid - 1 ;
        tmp[k++] = q[i++];
    }
    while(j <= r){
        tmp[k++] = q[j++];
    }
    for(int i = l , j = 0 ; i <= r ; j ++ , i ++){
        q[i] = tmp[j];
    }
}

int main()
{
    cin>>n;
    for(int i = 0 ; i < n ; i ++){
        cin>>q[i].x;
        q[i].y = i;
    }
    merge(0 , n - 1);
    LL res = 0 ; 
    for(int i = 0 ; i < n ; i ++) res += (LL)sum[i] * (sum[i]+1)/2;
    cout<<res;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1529316.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法之前缀和

题目1: 【模板】一维前缀和&#xff08;easy&#xff09; 方法一: 暴力解法, 时间复杂度O(n*q), 当n10^5, q 10^5, 时间复杂度为O(10^10), 会超时. 方法二: 前缀和: 快速求出数组中某一段连续区间的和. 第一步: 预处理出来一个前缀和数组dp: 1. dp[i]表示区间[1,i]里所有元…

“币安悬赏500万美元”,调查BOME内幕!创始人:谁控制了Meme,谁就控制了宇宙!

自去年11月开始&#xff0c;背靠美帝资本力量的Solana在FTX交易所暴雷后重新崛起。目前Sol价格已经从熊市的8美刀上涨至200刀附近。除了Sol本币上涨外&#xff0c;Solana生态也是快速发展。 这其中又以Meme币最为突出&#xff01;西方玩家正把所有的梗都搬进链上制成Meme币&am…

echarts geo地图加投影两种方法

方法1&#xff0c;geo中加多个地图图形&#xff0c;叠加。缩放时 可能会不一致&#xff0c;需要捕捉georoam事件&#xff0c;使下层的geo随着上层的geo一起缩放拖曳 geo: [{zlevel: 3,//geo显示级别&#xff0c;默认是0 【最顶层图形】map: BJ,//地图名roam: true,scaleLimit: …

[AIGC] MySQL与PostgreSQL:两种流行的数据库系统的对比

数据库是存储和查询数据的重要工具。在选择数据库时&#xff0c;两个经常被考虑的选项都是开源的&#xff1a;MySQL和PostgreSQL。这两个数据库都与许多应用程序一起使用&#xff0c;但它们在某些方面存在显著的不同。在本文中&#xff0c;我们将比较MySQL和PostgreSQL的一些关…

基金分析之与行业间的相关系数计算

这几年买了非常多的基金&#xff0c;一直很好奇基金在非业绩披露期都持有了什么东西&#xff1f;所以写了一个基金净值和各申万一级行业相关系数&#xff08;以及和市场主流指数&#xff09;的代码看看能否分析出点东西。 这里依然用了wind API&#xff0c;复现前记得安装。 …

超快速排序(蓝桥杯,归并排序,acwing)

题目描述&#xff1a; 在这个问题中&#xff0c;您必须分析特定的排序算法----超快速排序。 该算法通过交换两个相邻的序列元素来处理 n 个不同整数的序列&#xff0c;直到序列按升序排序。 对于输入序列 9 1 0 5 4&#xff0c;超快速排序生成输出 0 1 4 5 9。 您的任务是确…

JavaScript基础知识2

求数组的最大值案例 let arr[2,6,1,7,400,55,88,100]let maxarr[0]let minarr[0]for(let i1;i<arr.length;i){max<arr[i]?maxarr[i]:maxmin>arr[i]?minarr[i]:min}console.log(最大值是&#xff1a;${max})console.log(最小值是&#xff1a;${min}) 操作数组 修改…

企业专业化管理金字塔:技能进阶与案例分析

在纷繁复杂的企业管理领域中&#xff0c;一套行之有效的管理技能体系对于企业的稳健发展至关重要。本文将深入探讨企业专业化管理金字塔的五个层次&#xff1a;基本的管理技能、业务操作管理技能、组织管理技能、组织开发技能以及管理转变技能&#xff0c;并结合实际案例&#…

Java后端八股------设计模式

Coffee可以设计成接口。 b

代码随想录算法训练营第27天|93.复原IP地址、78.子集、90.子集二

目录 一、力扣93.复原IP地址1.1 题目1.2 思路1.3 代码1.4 总结 二、力扣78.子集2.1 题目2.2 思路2.3 代码2.4 总结 三、力扣90.子集二3.1 题目3.2 思路3.3 代码3.4 总结 一、力扣93.复原IP地址 &#xff08;比较困难&#xff0c;做起来很吃力&#xff09; 1.1 题目 1.2 思路 …

30.网络游戏逆向分析与漏洞攻防-网络通信数据包分析工具-数据搜索功能

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;29.数据推测功能…

解决MySQL “Lock wait timeout exceeded; try restarting transaction“ 错误

在处理MySQL数据库时&#xff0c;我们偶尔会遇到一个棘手的错误消息&#xff1a;“Lock wait timeout exceeded; try restarting transaction”。这通常表明我们的一个事务在尝试获取资源时被阻塞了太长时间。在并发环境中&#xff0c;多个事务同时竞争相同的资源可能会导致这种…

前端 - 基础 表单标签 -- 表单元素( input - type属性) 文本框和密码框

表单元素 &#xff1a; 在表单域中可以定义各种表单元素&#xff0c;这些表单元素就是允许用户在表单中输入或选择 的内容控件。 表单元素的外观也各不一样&#xff0c;有小圆圈&#xff0c;有正方形&#xff0c;也有方框&#xff0c;乱七八糟的&#xff0c;各种各样&#xf…

关系数据库:关系数据结构基础与概念解析

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

2024/03/19总结

算法&#xff1a; 简单的一个dfs就能过 ac: #include "iostream" #include "algorithm" #include "cstring" #include "queue" using std::cin; using std::cout; using std::endl; #define N 110 char a[N][N]; int abook[N][N]; i…

算法|基础算法|二分和双指针

数学与数论|二分 1.基础二分 2.双指针 心有猛虎&#xff0c;细嗅蔷薇。你好朋友&#xff0c;这里是锅巴的C\C学习笔记&#xff0c;常言道&#xff0c;不积跬步无以至千里&#xff0c;希望有朝一日我们积累的滴水可以击穿顽石。 基础二分 模板 bool check(int x){/*...*/} …

spring suite搭建springboot操作

一、前言 有时候久了没开新项目了&#xff0c;重新开发一个新项目&#xff0c;搭建springboot的过程都有点淡忘了&#xff0c;所有温故知新。 二、搭建步骤 从0开始搭建springboot 1&#xff0e;创建work空间。步骤FileNewJava Working Set。 2.选择Java Working Set。 3.自…

Java八股文(RabbitMQ)

Java八股文のRabbitMQ RabbitMQ RabbitMQ RabbitMQ 是什么&#xff1f;它解决了哪些问题&#xff1f; RabbitMQ 是一个开源的消息代理中间件&#xff0c;用于在应用程序之间进行可靠的异步消息传递。 它解决了应用程序间解耦、消息传递、负载均衡、故障恢复等问题。 RabbitMQ …

SpringCloud Bus 消息总线

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第八篇&#xff0c;即介绍 Bus 消息总线。 二、概述 2.1 遗留的问题 在上一篇文章的最后&#xff0c;我…

Gradle v8.5 笔记 - 从入门到进阶(基于 Kotlin DSL)

目录 一、前置说明 二、Gradle 启动&#xff01; 2.1、安装 2.2、初始化项目 2.3、gradle 项目目录介绍 2.4、Gradle 项目下载慢&#xff1f;&#xff08;万能解决办法&#xff09; 2.5、Gradle 常用命令 2.6、项目构建流程 2.7、设置文件&#xff08;settings.gradle.…