【备战秋招】每日一题:华东师范大学保研机试-2022-Minimum_Sum

news2024/11/24 2:32:06

为了更好的阅读体检,可以查看我的算法学习博客
在线评测链接:P1053

题目内容

你有一个序列a_1,a_2,...,a_n,然后给你一些区间[l,r].对于每一个区间,你需要找到下式的最小值,对于所有可能的x
\sum_{i=l}^{r}|x-a_i|

输入格式

第一行一个整数N(N \leq 10^5)代表序列长度。

接下来一行有N个正整数a_i(1 \leq a_i \leq 10^9),用空格隔开。

接下来一行一个整数Q(1 \leq Q \leq 10^5),代表询问的区间次数。

接下来Q行,每行一个区间l,r(1 \leq l \leq r \leq N)

输出格式

输出Q行。每行代表对应的区间的结果。

样例

5
2 3 3 4 4
3
1 2
2 2
2 5
1
0
2

思路:可持久化线段树

我们一步步剖析这道题。

对于a_l, a_{l+1}, \cdots a_{r-1}, a_{r}这些数,想要找到一个数 x ,使得 \sum\limits_{i=l}^r |a_i-x|最小,则 x 必然是这些数的中位数。详见下方证明。

统计a_l, a_{l+1}, \cdots a_{r-1}, a_{r} 这些数中,小于等于中位数的数的和为 ltSum,个数为 ltCnt,统计大于中位数的数的和为 gtSum,个数为 gtCnt。

\sum\limits_{i=l}^r |a_i-x|=(ltCnt \times x - ltSum)+(gtSum-gtCnt\times x)

因为最多有 10^5次询问,所以单次询问的时间复杂度至多为 O(\log n)

如此,我们需要一个数据结构能够在O(\log n)的时间内获得区间 [l, r] 的中位数。

再通过这个数据结构获取到

  • 小于这个中位数的所有数之和 ltSum,以及所有数的数量 ltCnt

  • 大于这个中位数的所有数之和 gtSum,以及所有数的数量 gtCnt

这个数据结构叫作主席树,也叫可持久化线段树,可以用来求解区间第 k 大。

点击查看主席树教程

时间复杂度:因为 n 与 Q 同阶,故时间复杂度为 O(n\log n)

证明:

假设a_l, a_{l+1},\cdots a_{r-1}, a_{r} 是单调递增的。

  • a_l\leq x \leq a_r|a_l-x|+|a_r-x|=a_r-a_l

  • x < a_l|a_r-x|>a_r-a_l|a_l-x|>0|a_l-x|+|a_r-x|>a_r-a_l

  • x > a_r|a_r-x|>0|a_l-x|>a_r-a_l,|a_l-x|+|a_r-x|>a_r-a_l

a_l\leq x \leq a_r|a_l-x|+|a_r-x|=a_r-a_l最小。

a_{l+1} 和 a_{r-1} ,分析过程与上类似,a_{l+1}\leq x\leq a_{r-1}以此类推,x 应该为a_l, a_{l+1}, \cdots a_{r-1}, a_{r}的中位数。

代码

#include <bits/stdc++.h>
using namespace std;
​
#define sz(x) (int(x.size()))
​
typedef long long ll;
​
const int N = 100010;
int a[N], n, Q;
vector<int> nums;
​
// 获取每个点离散化后的下标
int get_idx(int x) {
    return int(lower_bound(nums.begin(), nums.end(), x) - nums.begin());
}
​
struct Node {
    int l, r;
    int cnt;
    ll sum;
}tr[N * 21];
​
// 每个点的root
int root[N], idx;
​
// 初始化
int build(int l, int r) {
    int p = ++idx;
    if (l == r) return p;
    int mid = (l + r) >> 1;
    tr[p].l = build(l, mid);
    tr[p].r = build(mid + 1, r);
    return p;
}
​
// 插入新的点
int insert(int p, int l, int r, int x) {
    int q = ++idx;
    tr[q] = tr[p];
    if (l == r) {
        tr[q].cnt += 1;
        tr[q].sum += nums[x];
        return q;
    }
    int mid = (l + r) >> 1;
    if (x <= mid) tr[q].l = insert(tr[p].l, l, mid, x);
    else tr[q].r = insert(tr[p].r, mid + 1, r, x);
    tr[q].cnt = tr[tr[q].l].cnt + tr[tr[q].r].cnt;
    tr[q].sum = tr[tr[q].l].sum + tr[tr[q].r].sum;
    return q;
}
​
// 求区间第 k 大
int query_kth_number_idx(int q, int p, int l, int r, int k) {
    if (l == r) return l;
    int lcnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
    int mid = (l + r) >> 1;
    if (k <= lcnt) return query_kth_number_idx(tr[q].l, tr[p].l, l, mid, k);
    return query_kth_number_idx(tr[q].r, tr[p].r, mid + 1 , r, k - lcnt);
}
​
// 求区间内与 x 的距离之和
ll query_sum_of_dist(int q, int p, int l, int r, int x) {
    if (l == r) return 0;
    int mid = (l + r) >> 1;
    if (x <= nums[mid]) {
        // 说明右子树的值全部大于 x,gtSum - gtCnt * x
        ll gtSum = tr[tr[q].r].sum - tr[tr[p].r].sum;
        ll gtCnt = tr[tr[q].r].cnt - tr[tr[p].r].cnt;
        return (gtSum - gtCnt * x) + query_sum_of_dist(tr[q].l, tr[p].l, l, mid, x);
    } else {
        // 说明左子树的值全部小于 x,ltCnt * x - ltSum
        ll ltCnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
        ll ltSum = tr[tr[q].l].sum - tr[tr[p].l].sum;
        return (ltCnt * x - ltSum) + query_sum_of_dist(tr[q].r, tr[p].r, mid + 1, r, x);
    }
}
​
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        nums.push_back(a[i]);
    }
​
    // 离散化
    sort(nums.begin(), nums.end());
    nums.erase(unique(nums.begin(), nums.end()), nums.end());
​
    // 构建可持久化权值线段树
    root[0] = build(0, sz(nums) - 1);
    for (int i = 1; i <= n; ++i) {
        root[i] = insert(root[i - 1], 0, sz(nums) - 1, get_idx(a[i]));
    }
​
    scanf("%d", &Q);
    while (Q--) {
        int l, r;
        scanf("%d%d", &l, &r);
        // 获取中位数,注意这里中位数的索引应该从 1 开始
        int k = (r - l + 1 + 1) / 2;
        int kidx = query_kth_number_idx(root[r], root[l - 1], 0, sz(nums) - 1, k);
        printf("%lld\n", query_sum_of_dist(root[r], root[l - 1], 0, sz(nums) - 1, nums[kidx]));
    }
​
    return 0;
}

 题目内容均收集自互联网,如如若此项内容侵犯了原著者的合法权益,可联系我: (CSDN网站注册用户名: 塔子哥学算法) 进行删除。

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

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

相关文章

Ansys Speos | 2023R2 新功能介绍

Speos 2023R2 新功能集中在优化、交互设计、GPU的更新&#xff0c;Speos将提供嵌入界面的优化工具&#xff0c;简化Speos和optiSLang的联合优化&#xff0c;交互式实时预览提供无限方案探索&#xff0c;Block Recording块记录更加整洁清晰&#xff0c;GPU对Rayfile光源的支持满…

第九届“互联网+”大赛产业赛道百度命题正式公布!57道命题,等你揭榜!

2023年6月28日&#xff0c;中国国际“互联网”大学生创新创业大赛组委会正式发布了《关于公布第九届中国国际“互联网”大学生创新创业大赛产业命题赛道入选命题的通知》&#xff0c;百度共有五十七道命题成功入围产业赛道&#xff0c;入围数居全国前列。 中国国际“互联网”大…

InsCode Stable Diffusion 美图活动投稿

本地部署可以使用B站大佬秋叶的整合包 CSDN亦提供了Stable Diffusion 模型在线使用地址&#xff1a;https://inscode.csdn.net/inscode/Stable-Diffusion 模型相关版本和参数配置&#xff1a; 模型&#xff1a;cetusversion4.WRgK.safetensors [b42b09ff12] VAE&#xff1a;y…

Vivado_Cordic IP核使用详解

本文介绍Vivado中CORDIC V6.0的使用方法。 参考资料&#xff1a;pg105 文章目录 IP核配置CORDIC算法Vector RotationPolar to Rectangular Vector translationSin and CosSinh and CoshArcTanArcTanhSquare Root IP核配置 Configuration Options选项卡 Configuration Paramet…

银河麒麟服务器v10 sp1 安装 redis

1、下载redis安装包 https://download.redis.io/releases/ 本文下载redis-7.0.11.tar.gz包&#xff0c;请按照自己需求下载相应文件。 2、将下载后的.tar.gz压缩包上传到到服务器自定义文件夹下 本人上传为系统的下载文件夹下&#xff0c;可以直接上传至指定目录下&#xff…

Linux发行版Gentoo被发现有漏洞,在SQL注入方面存在安全风险

近日有消息表明&#xff0c;Gentoo Linux发行版中存在漏洞CVE-2023-28424&#xff0c;并且极有可能被黑客利用该漏洞进行SQL注入攻击。 据悉&#xff0c;研究人员从 GentooLinux的Soko搜索组件中找到了这个漏洞&#xff0c;并且该漏洞的CVSS风险评分为 9.1&#xff0c;属于特别…

两数相加问题

给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会以 0 …

Linux 进程虚拟地址空间与虚拟内存

Linux 进程虚拟地址空间与虚拟内存 本文主要介绍Linux进程虚拟地址空间和虚拟内存的概念&#xff0c;学习可用物理内存中的页帧与所有的进程虚拟地址空间中的页之间的关联&#xff1a; 逆向映射&#xff08;reverse mapping&#xff09; 技术有助于从虚拟内存页追踪到对应的物…

ASS字幕 中的阴影 如何去除,三秒解决

有些外挂的ass字幕&#xff0c;总是自带一层浓浓的 阴影&#xff0c;看着就很不舒服&#xff0c;如下截图 解决方法&#xff1a; 鼠标右键&#xff0c;用记事本打开ass字幕文件&#xff0c;然后搜索关键字 ScaledBorderAndShadow&#xff0c;将其后面的 yes 改为 no&#xff0…

JSP在线小说系统用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 JSP 在线小说系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0&#xff0c;使用ja…

C. Insert Zero and Invert Prefix - 构造+思维

分析&#xff1a; 数组b的最后一个元素永远不可能使1&#xff0c;因为即使在最后一个位置操作&#xff0c;也只会把前n-1个元素反转&#xff0c;最后一个元素只能为0.然后可以发现只要a[i]0就可以直接输出0&#xff0c;当a[i]1时一连串的1只需要最后一个1的位置改变成1的字串长…

微信小程序基础语法

微信小程序 文章目录 微信小程序[toc]一、初识微信小程序1.什么是微信小程序2.小程序可以做什么3.小程序与普通网页开发的区别 二、开发准备1.注册小程序开发账号2.安装开发者工具3.登陆我们的开发者工具 三、小程序构成1.小程序的基本组成结构2.小程序的页面组成结构3.小程序组…

OSI(开放系统互连参考模型)知识点详细介绍!!

开放系统互连参考模型分七层&#xff0c;从低到高是物理层&#xff0c;数据链路层&#xff0c;网络层&#xff0c;传输层&#xff0c;会话层&#xff0c;表示层和应用层 一.物理层&#xff08;Physical Layer&#xff09; 物理层位于 OSI/RM 参考模型的最底层&#xff0c;为数…

6.18、Java初级异常

1. 异常概述 1.1 什么是生活的异常 男主角小明每天开车上班&#xff0c;正常车程 1 小时。但是&#xff0c;可能会出现意外&#xff0c;出现意外&#xff0c;即为异常情况。我们会做相应的处理。如果不处理&#xff0c;到不了公司。 处理完了&#xff0c;就可以正常开车去公司…

浪涌保护器的标准和应用领域综合方案

浪涌保护器是一种用于防止电力系统或电子设备受到雷击或其他暂态过电压的损坏的装置。根据国家标准GB/T 18802.11-20201&#xff0c;低压电涌保护器 (SPD) 应符合IEC 61643-11:2011的性能要求和试验方法。浪涌保护器的产品参数包括&#xff1a;额定工作电压、最大连续工作电压、…

【kubernetes系列】kubernetes之kube-proxy的工作模式

概述 从kubernetes最早开始&#xff0c;kube-proxy到现在总共支持三种模式&#xff0c;在v1.8之前我们使用的是iptables 以及 userspace两种模式&#xff0c;iptables 模式从 v1.2 版本开始引入并作为kube-proxy 默认的操作模式。在kubernetes 1.8之后引入了ipvs模式&#xff…

!!!已解决: Linux操作系统登录,输入正确账号密码显示却显示:Sorry, that didn‘t work. Please try again.

&#xff01;&#xff01;&#xff01;已解决&#xff1a; Linux操作系统登录&#xff0c;明明输入密码正确却显示&#xff1a;Sorry, that didn’t work. Please try again. 先给大家复现一下我的问题&#xff1a; 为什么出现这个问题&#xff1f;&#xff1f;&#xff1f; …

知识梳理for CDGA/CDGP——第九章 ​文件和内容管理

第九章在CDGA分值占比较少&#xff0c;CDGP不考核&#xff0c;主要考点包括&#xff1a;定义、目标、原则、活动、工具、度量指标等基本概念、记住精心管理档案特点、GARP原则等。因此本章建议不需要花大量时间研究&#xff0c;熟悉历史真题&#xff0c;聚焦关键考点即可&#…

Leetcode-每日一题【1290. 二进制链表转整数】

题目 给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。 请你返回该链表所表示数字的 十进制值 。 示例 1&#xff1a; 输入&#xff1a;head [1,0,1]输出&#xff1a;5解释&#xff1a;二进制数 (101) 转化为…

没有BuildConfig

Android Gradle 插件8.0.0&#xff08;2023年4月&#xff09; 刚刚发现&#xff0c;新创建的一个Android项目&#xff0c;成功运行到手机上了&#xff0c;然后在代码中想使用一下BuildConfig这个类&#xff0c;发现没有&#xff0c;按以前的经验&#xff0c;项目刚创建时Build…