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

题目描述:

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.mfbz.cn/a/470143.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决NameError:name ‘file‘ is not defined 方法

方法1&#xff1a; import os base_diros.path.dirname(os.path.realpath(_file_) print(base_dir)方法2&#xff1a; import os base_diros.getcwd() print(base_dir)

PTA一笔画

作者 张志梅 单位 青岛大学 小丁最近迷恋上一个游戏&#xff0c;传说中的“一笔画”游戏。 那么什么是一笔画&#xff1f;如下图&#xff0c;顾名思义就是一笔可以完成的图。一笔画最基本的要求是在画图的过程中&#xff0c;笔不能离开纸&#xff0c;且笔所画过的线不能重复…

SAR ADC系列6——比较器输入失调电压仿真

ADC中比较器输入失调电压的仿真方法 比较器输入端输入一个共模电平&#xff08;1.65V&#xff09;&#xff0c;一个斜坡信号&#xff08;1.64V-1.66V&#xff09; 时序大概长下面这样 测量在发生翻转时的输入电压之间的差值&#xff0c;进行多次蒙特卡洛的仿真 用公式计算发…

【DNDC模型】土壤碳储量、温室气体排放、农田减排、土地变化、气候变化

由于全球变暖、大气中温室气体浓度逐年增加等问题的出现&#xff0c;“双碳”行动特别是碳中和已经在世界范围形成广泛影响。国家领导人在多次重要会议上讲到&#xff0c;要把“双碳”纳入经济社会发展和生态文明建设整体布局。同时&#xff0c;提到要把减污降碳协同增效作为促…

mapstruct学习笔记-pojo之间的转换

1、前言 mapstruct中常用注解如Mapping,AfterMapping,BeanMapping等的使用,通过案例说明各式各样的业务pojo对象之间如何借助mapstruct完成相互之间的转换,减少代码量的同时也能突出业务逻辑流程,让你的代码里写起来更有规范可言。 2、简介 Reference Guide – MapStruct 3…

mysql中的非空间数据导入sqlserver中空间化

以下操作都在Navicat Premium 15软件中操作 1、mysql导出数据 以导出csv为例 不修改导出路径的话默认就是在桌面 设置编码UTF-8 这边还是默认,最好不要修改,如果文本识别符号为空,导入的时候可能字段会错乱 开始即可 2、导入sqlserver数据库中

排序——直接插入排序

排序之——直接插入排序 插入排序的基本思想 每次将一个待排序的记录按其关键字大小插入前面已经排好序的子序列&#xff0c;直到全部记录插入完成。 步骤&#xff08;从小到大排序&#xff09; 找到没有排序的元素标记元素将已排好序的序列中大于标记元素的往后移插入元素 …

从Excel到山海鲸:我的数据可视化升级之旅

作为一名新用户&#xff0c;我最近有幸体验了山海鲸可视化软件&#xff0c;近期山海鲸可视化产品开放了可视化编辑全部功能&#xff0c;并支持本地化部署功能&#xff0c;在使用过程中它不仅打开了我对数据可视化全新世界的大门&#xff0c;而且在实际操作中为我带来了不少惊喜…

深圳市蕾奥规划设计咨询股份有限公司入围《信用中国》栏目

为进一步推进商业信用体系建设,促进企业诚实守信经营,面向企业普及诚信与品牌建设的意义,指导企业加强诚信品牌建设,提升其整体竞争力,《信用中国》栏目组以诚信为内涵,在全国范围内遴选出有行业代表性的民营企业作为扶持对象,旨在通过大力宣传自主品牌,提高自主品牌影响力和认…

牛客NC241 计算器(二)【中等 dfs+双端队列 Java】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/a9c170bfaf7349e3acb475d786ab1c7d 核心 DFS双端队列参考答案Java import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定…

算法学习(持续更新中)

时间复杂度 一个操作如果和样本的数据量没有关系&#xff0c;每次都是固定时间内完成的操作&#xff0c;叫做常数操作。 时间复杂度为一个算法流程中&#xff0c;常数操作数量的一个指标。常用O&#xff08;读作big O&#xff09;来表示。具体来说&#xff0c;先要对一个算法…

2024同城定位付费进群完整源码支付也能用

2024同城定位付费进群完整源码支付也能用 最近有几个朋友和我咨询这个项目&#xff0c;但是找了几个后大多都不完整不能用&#xff0c;好吧&#xff0c;给大家找了一套完美修复的出来&#xff0c;并且对接好了免签支付&#xff0c;可以直接使用&#xff0c;搭建简单&#xff0…

equals与时间序列攻击

引言 随着信息技术的迅速发展&#xff0c;网络安全和隐私问题变得愈发重要。黑客和攻击者不断寻找新的攻击方法&#xff0c;其中之一是时间序列攻击&#xff08;Timing Attack&#xff09;。时间序列攻击是一种侧信道攻击&#xff0c;攻击者试图通过测量程序的执行时间来推断程…

408-数据结构笔记(自用)

1.绪论 数据结构的概念&#xff1a;即数据的 逻辑结构、存储结构和运算 数据的基本单位是数据元素&#xff0c;一个数据元素由若干数据项组成&#xff0c;比如Student是一个数据元素&#xff0c;年龄、性别、学号等都是数据项 &#xff08;1&#xff09;逻辑结构 数据的逻辑…

【计算机考研】408全年复习保姆级规划+资料

基础阶段 408一共只分为选择题和大题&#xff0c;选择题80分&#xff0c;大题70分。 基础阶段应该要形成相对完整的知识体系&#xff0c;基础知识大概都需要有印象。 在基础阶段&#xff0c;建议不做大题&#xff0c;把课后选择题都好好的做一遍 第一遍的正确率无需过于关注…

WEB搭建LNMP环境-Discuz论坛

目录 一、安装PHP并修改配置文件(nginx自行安装) 二、安装MySQL数据库并配置文件 三、 搭建discuz论坛 一、安装PHP并修改配置文件(nginx自行安装) yum install php php-gd php-fpm php-mysqlnd php-xml -y vim /etc/nginx/nginx.conf #配置nginx和PHP交互location …

三、转移字符、字符串、bool类型和eval函数

一、转义字符 \n&#xff1a;换行符 \t&#xff1a;制表符 \&#xff1a;单引号 \"&#xff1a;双引号 \\&#xff1a;反斜杠 a人生无常 b我用python print(ab) print(f"{a}\n{b}") print(f"{a}\t{b}") print(fr"{a}\t{b}") 在打印字…

科研学习|研究方法——实验法

1.实验方法的渊源 今天我们说物理学、生物学是实验的科学&#xff0c;应该不会有人再持异议了&#xff0c;然而连物理学这样的学科在历史上也并非一开始就是实验科学。在2000多年以前的亚里士多德时代&#xff0c;众人都认为物理学是非实验性质的&#xff0c;物理学成为实验科学…

F-logic DataCube3 任意文件上传漏洞复现(CVE-2024-25832)

0x01 产品简介 F-logic DataCube3是一款用于光伏发电系统的紧凑型终端测量系统。 0x02 漏洞概述 F-logic DataCube3 /admin/setting_photo.php接口处存在任意文件上传漏洞 ,未经身份验证的攻击者可通过该漏洞在服务器端写入后门,获取服务器权限,进而控制整个web服务器。 …

Nginx发布之后可以使用IP访问,不能使用localhost访问, Nginx发布之后可以使用localhost访问,不能使用IP访问,

如标题所说 Nginx发布之后可以使用IP访问&#xff0c;不能使用localhost访问&#xff0c; Nginx发布之后可以使用localhost访问&#xff0c;不能使用IP访问&#xff0c; 修改配置文件也没有用 清除浏览器缓存数据