CF104064 E. Exchange Students(NWERC2021)

news2025/7/14 20:25:03

题目分析

在这里插入图片描述

首先需要观察到一个性质:在最优方案下的操作一定是首先交换距离最近能交换的两个点来达到交换的效果,这个很好理解:题目要求如果要交换两个人的位置,中间的人的身高必须严格小于这两个人,因此合法的交换操作仅可能发生在距离最近的可交换点对之间。每次交换花费仅可能耗费一次操作。

那么我们可以发现,如果从身高最小的往上交换,每次的操作次数等同于:
a b s ( ( 在 g 数 组 中 交 换 到 首 位 的 操 作 步 数 ) − ( 在 h 数 组 中 交 换 到 首 位 的 操 作 次 数 ) ) abs((在g数组中交换到首位的操作步数) - (在h数组中交换到首位的操作次数)) abs((g)(h))
为什么要从身高最小的向上交换?因为当身高小的到达正确位置后,不会再对后续身高更高的交换操作产生影响

那么我们发现交换的首位的操作次数实际上就是求个逆序对即可。然后按顺序统计答案即可。

那么如何求操作序列呢?我们仍按照上述的策略来确定操作,但是我们很快会发现:每次操作我们都需要很快快的求得以下几个量:假设当前位置为 p p p

  • 求得首个 l _ m a x ≤ p l\_max \leq p l_maxp g [ l _ m a x ] ≥ g [ p ] g[l\_max] \geq g[p] g[l_max]g[p]
  • 求得首个 r _ m a x ≥ p r\_max \geq p r_maxp g [ r _ m a x ] ≥ g [ p ] g[r\_max] \geq g[p] g[r_max]g[p]

然后我们会很熟悉的发现,只需要上个线段树+二分就可以解决这个问题。但是这样做还是有个问题:

在这里插入图片描述

如果存在连续相等的序列,那么就求错了,因为跨过了一大段无意义的交换。这该怎么办呢?

假设原始位置为 a a a,待抵达位置为 b b b,分类讨论:

  • 如果 a < b a < b a<b
    • 每次交换时,先找到 a a a右侧最近的 r _ m a x r\_max r_max,然后对 r _ m a x r\_max r_max找到左侧最近的 l _ m a x l\_max l_max(注意这里的 l _ m a x l\_max l_max是相对 h [ r _ m a x ] h[r\_max] h[r_max]而言的, r _ m a x r\_max r_max是相对 h [ a ] h[a] h[a]而言的),然后使用该 l _ m a x l\_max l_max r _ m a x r\_max r_max进行交换即可。
  • 如果 a > b a > b a>b:
    • 每次交换时,先找到 a a a左侧最近的 l _ m a x l\_max l_max,然后对 l _ m a x l\_max l_max找到右侧最近的 r _ m a x r\_max r_max,然后使用该 l _ m a x l\_max l_max r _ m a x r\_max r_max进行交换即可。

上面两个过程实际上是一对镜像操作。如此一来,就避免的无意义的连续相等段内的交换(这些段的错误贡献实际上在逆序对统计时也没有统计到答案里(前提是要稳定排序否则会错),但是却会影响操作的构造)。

剩下的模拟上述过程即可。注意排序必须要稳定排序!否则会使逆序对计数产生错误(连续相同段)。

再注意,输出上限 2 e 5 2e5 2e5不要企图像HeartFireSB一样输出所有答案

Code

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
// 15016413052
const int N = 4e5 + 10, INF = 1e9 + 7;
int g[N], h[N];

struct Fenwick{
    int tree[N], len;
    #define lowbit(x) ((x) & (-x))
    inline void update(int i, int x){
        for(int pos = i; pos <= len; pos += lowbit(pos)) tree[pos] += x;
    }

    inline int getsum(int i, int ans = 0){
        for(int pos = i; pos > 0; pos -= lowbit(pos)) ans += tree[pos];
        return ans;
    }
    inline int query(int l, int r) {
        return getsum(r) - getsum(l - 1);
    }
} fh, fg;

int idg[N], idh[N], gid[N], n;

namespace SegTree{
    #define ls rt << 1
    #define rs rt << 1 | 1
    #define lson ls, l, mid
    #define rson rs, mid + 1, r

    int tree[N << 2];
    
    inline void push_up(int rt) { tree[rt] = max(tree[ls], tree[rs]); }

    void update(int rt, int l, int r, int pos, int val) {
        if(l == r) return tree[rt] = val, void();
        int mid = l + r >> 1;
        if(mid >= pos) update(lson, pos, val);
        else update(rson, pos, val);
        push_up(rt);
    }
    // L = 1, R = pos
    int queryl(int rt, int l, int r, int pos, int val) {
        if(l == r) { 
            if(tree[rt] >= val) return l;
            else return -1;
        }
        if(l >= 1 && r <= pos && tree[rt] < val) return -1;
        int mid = l + r >> 1;
        if(mid >= pos) return queryl(lson, pos, val);
        int res = queryl(rson, pos, val);
        if(res != -1) return res;
        return queryl(lson, pos, val);
    }
    // L = pos, R = n
    int queryr(int rt, int l, int r, int pos, int val) {
        if(l == r) {
            if(tree[rt] >= val) return l;
            return INF;
        }
        if(l >= pos && r <= n && tree[rt] < val) return INF;
        int mid = l + r >> 1;
        if(mid < pos) return queryr(rson, pos, val);
        int res = queryr(lson, pos, val);
        if(res != INF) return res;
        return queryr(rson, pos, val);
    }
}

inline void solve() {
    cin >> n; 
    fh.len = fg.len = n + 10;
    for(int i = 1; i <= n; i++) cin >> g[i];
    for(int i = 1; i <= n; i++) cin >> h[i];
    iota(idg, idg + 10 + n, 0);
    iota(idh, idh + 10 + n, 0);
    stable_sort(idg + 1, idg + 1 + n, [&](int a, int b){ return g[a] < g[b]; });
    stable_sort(idh + 1, idh + 1 + n, [&](int a, int b){ return h[a] < h[b]; });
    int cnt = 0;
    for(int i = 1; i <= n; i++) {
        int a = idg[i], b = idh[i];
        fg.update(a, 1);
        fh.update(b, 1);
        cnt += abs((a - fg.getsum(a)) - (b - fh.getsum(b)));
        // cout << "cnm -> " << a << ", " << b << " :: " << abs((a - fg.getsum(a)) - (b - fh.getsum(b))) << endl;
    }
    cout << cnt << endl;
    if(cnt == 0) return;   
    for(int i = 1; i <= n; i++) SegTree::update(1, 1, n, i, g[i]);
    for(int i = 1; i <= n; i++) gid[idg[i]] = i;
    // for(int i = 1; i <= n; i++) cout << gid[i] << " \n"[i == n];
    int moves_cnt = 0;
    auto op = [&](int a, int b) {
        // if(moves_cnt >= cnt) return;
        swap(g[a], g[b]);
        swap(gid[a], gid[b]);
        swap(idg[gid[a]], idg[gid[b]]);
        SegTree::update(1, 1, n, a, g[a]);
        SegTree::update(1, 1, n, b, g[b]);
        cout << a << " " << b << endl;
        if(++moves_cnt == 200000) exit(0);
    };
    for(int k = 1; k <= n; k++) {
        int a = idg[k], b = idh[k];
        // cout << "NEW ROUND #" << k << endl;
        while(a < b) {
            int rmax = SegTree::queryr(1, 1, n, a, g[a] + 1);
            if(rmax > n) break;
            int lmax = SegTree::queryl(1, 1, n, rmax - 1, g[a]);
            // cout << "#Query1 -> a = " << a << ", b = " << b << "; rmax = " << rmax << ", lmax = " << lmax << endl;
            op(lmax, rmax);
            if(lmax == a) a = rmax;
        }

        while(a > b) {
            int lmax = SegTree::queryl(1, 1, n, a, g[a] + 1);
            if(lmax < 1) break;
            int rmax = SegTree::queryr(1, 1, n, lmax + 1, g[a]);
            // cout << "#Query2 -> a = " << a << ", b = " << b << "; lmax = " << lmax << ", rmax = " << rmax << endl;
            op(lmax, rmax);
            if(rmax == a) a = lmax;
        }
        // cout << "idg: ";
        // for(int i = 1; i <= n; i++) cout << idg[i] << " \n"[i == n];
    }
    for(int i = 1; i <= n; i++) assert(g[i] == h[i]);
}

signed main() {
    //    freopen("stdin.in", "r", stdin);
    //    freopen("stdout2.out", "w", stdout);
    ios_base::sync_with_stdio(false), cin.tie(0);
    solve();
    return 0;
}

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

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

相关文章

生成对抗网络(GAN)

GAN简介 GAN思想是一种二人的零和博弈思想&#xff0c;GAN中有两个博弈者&#xff0c;一个生成器&#xff08;G&#xff09;&#xff0c;一个判别器&#xff08;D&#xff09;&#xff0c;这两个模型都有各自的输入和输出。具体功能如下&#xff1a; 生成器&#xff08;G&…

声门脉冲语音处理

对于 0<t<tpeak&#xff0c;gattack(t) 攻击部分&#xff0c;即上升分支的时间&#xff0c;时间 t 的范围从 0 秒到最大峰值时间 tpeak &#xff0c;图示例中选择为大约总长度的 35%&#xff0c;即 tpeak35%⋅T0&#xff0c;或者在样本 Lattack⌊35%⋅Lg⌉ 中&#xff0c…

2023年系统规划与设计管理师-第三章信息技术服务知识

一. 思维导图 二.IT 服务管理 (ITSM) 1. 什么是 IT 服务管理 (ITSM)&#xff1f; IT 服务管理 (ITSM) 包含一组策略和实践&#xff0c;这些策略和实践可用于为最终用户实施、交付和管理 IT 服务&#xff0c;以满足最终用户的既定需求和企业的既定目标。 在此定义中&#xff0…

otn 709帧结构

otn架构说明: 基于G.709接口,包括波分侧和客户侧,客户侧通常用于互联互通。 光通路净荷单元:OPU0/OPU1/OPU2/OPU3/OPU4/flex,主要用于完成业务同步或异步映射; 光通路数据单元:ODU0/ODU1/ODU2/ODU3/ODU4/ODU-flex,完成通道连接性能监测和子速率复用、 光通路传送单元…

POJ1008:玛雅日历

一、Description During his last sabbatical, professor M. A. Ya made a surprising discovery about the old Maya calendar. From an old knotted message, professor discovered that the Maya civilization used a 365 day long year, called Haab, which had 19 months.…

Netty学习笔记

文章目录二、Netty 入门2.1、概述2.1.1、Netty 是什么&#xff1f;2.1.2、Netty 的作者2.1.3、Netty 的地位2.1.4、Netty 的优势2.2、Hello World2.2.1、目标2.2.2、服务器端2.2.3、客户端2.2.4、流程梳理&#x1f4a1; 提示2.3、组件2.3.1、EventLoop&#x1f4a1; 优雅关闭演…

保姆级二进制安装高可用k8s集群文档(1.23.8)

保姆级二进制安装高可用k8s集群文档k8s搭建方式前期准备集群规划机器准备1、master vagrantfile2、master install.sh3、node vagrantfile4、node install.sh5、时间同步vagran 启动脚本vagrant up注意点安装conntrack 工具ipvs的安装VBoxManage snapshot 准备虚拟机快照ETCD部…

C语言编程作业参考答案

编程题参考答案 文章目录编程题参考答案week1_test选择结构-编程题循环结构上机练习数组编程函数编程2week1_test Write a program to output the average of 2 integers. #include <stdio.h>void main(){int a , b;double c;printf("Please enter 1 integers\n&q…

官网下载mysql 8.0.27及安装

https://www.mysql.com/downloads/&#xff0c;找到社区版下载链接MySQL Community (GPL) Downloads 1、 2、 3、 4、 5、

光谱异常样本检测分析

以近红外光谱为例&#xff0c;大部分光谱数据在不考虑分类问题时&#xff0c;在构建模型前需要对采集数据进行样本分析&#xff0c;以降低因生产过程异常、人为误操作和其他原因对软测量模型的影响&#xff0c;即异常样本检测分析。 按照定义&#xff0c;异常样本检测任务指的是…

k8s编程operator——(3) 自定义资源CRD.md

文章目录1、自定义资源的使用1.1 注册自定义资源1.2 使用自定义资源&#xff1a;1.3 Finalizers1.4 合法性验证2、如何操作自定义资源2.1 使用RestClient和DynamicClient来操作自定义资源对象2.2 使用sharedIndexInformer2.3 code-generator2.3.1 下载安装2.3.2 code-generator…

Ajax、Fetch、Axios三者的区别

1.Ajax&#xff08;Asynchronous JavaScript And XML&#xff09; Ajax 是一个技术统称&#xff0c;它很重要的特性之一就是让页面实现局部刷新。 特点&#xff1a; 局部刷新页面&#xff0c;无需重载整个页面。 简单来说&#xff0c;Ajax 是一种思想&#xff0c;XMLHttpReq…

毕业设计-基于机器学习的图片处理图片倾斜校正

前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科同学来说是充满挑战。为帮助大家顺利通过和节省时间与精力投…

如何简单理解大数据

如何简单理解大数据 HDFS-存储 海量的数据存储 hadoop 只是一套工具的总称&#xff0c;它包含三部分&#xff1a;HDFS&#xff0c;Yarn&#xff0c;MapReduce&#xff0c;功能分别是分布式文件存储、资源调度和计算。 按理来说&#xff0c;这就足够了&#xff0c;就可以完成大…

matlab实现MCMC的马尔可夫转换MS- ARMA - GARCH模型估计

状态转换模型&#xff0c;尤其是马尔可夫转换&#xff08;MS&#xff09;模型&#xff0c;被认为是识别时间序列非线性的不错的方法。 估计非线性时间序列的方法是将MS模型与自回归移动平均 - 广义自回归条件异方差&#xff08;ARMA - GARCH&#xff09;模型相结合&#xff0c;…

Ubuntu22.04+Nvidia驱动+Cuda11.8+cudnn8.6

Ubuntu22.04Nvidia驱动Cuda11.8 一、准备环境 ubuntu 22.04nvidia显卡 这里使用的是RTX3060已安装Python3.10 二、安装pip3 # 安装 sudo apt install python3-pip # 升级 sudo pip3 install --upgrade pip # 如果要卸载&#xff0c;使用命令&#xff1a; sudo apt-get remov…

MySQL创建和管理表

基础知识 一条数据存储的过程 存储数据是处理数据的第一步 。只有正确地把数据存储起来&#xff0c;我们才能进行有效的处理和分析。否则&#xff0c;只能是一团乱麻&#xff0c;无从下手。 那么&#xff0c;怎样才能把用户各种经营相关的、纷繁复杂的数据&#xff0c;有序、…

ES6解析赋值

ES6中新增了一种数据处理方式&#xff0c;可以将数组和对象的值提取出来对变量进行赋值&#xff0c;这个过程时将一个数据结构分解成更小的部分&#xff0c;称之为解析。 1.对象解析赋值: 在ES5中&#xff0c;要将一个对象的属性提取出来&#xff0c;需要经过一下几个过程。 …

aws sdk 学习和使用aws-sdk-go

https://www.go-on-aws.com/infrastructure-as-go/cdk-go/sdk example&#xff0c;https://github.com/awsdocs/aws-doc-sdk-examples golang的安装&#xff0c;使用1.15之后默认开启GO15VENDOREXPERIMENT的版本 yum install golang -y go env -w GOPROXYhttps://goproxy.cn,…

智慧教室解决方案-最新全套文件

智慧教室解决方案-最新全套文件一、建设背景1、教育信息化2.0行动计划2、中国教育现代化20353、加快推进教育现代化实施方案二、建设思路互联网时代教学环境定义三、建设方案四、获取 - 智慧教室全套最新解决方案合集一、建设背景 1、教育信息化2.0行动计划 “网络学习空间覆…