本题为3月13日23上半学期集训每日一题中A题的题解
某石油公司计划建造一条由东向西的主要输油管道。该管道要穿过一个有n口油井的油田。从每口油井都要有一条输油管道沿最短路径(或南或北)与主管道相连。如果给定n口油井的位置,及它们的x坐标(东西向)和y坐标(南北向),应如何确定主管道的最优位置,即使各油井到主管道之间的输油管道长度总和最小的位置?证明可规定时间内确定主管道的最优位置。
注:为方便铺设,要求主管道铺设在整数位置点
第一行是油井数n( \(1 \leq n \leq 10000\) )
接下来n行是油井的位置,每行2个整数x和y( \(-10000 \leq x,y \leq 10000\) )
只有一行
油井到主管道之间的输油管道最小长度总和
5
1 2
2 2
1 3
3 -2
3 3
6
本题是一个经典的中位数模型问题.
首先,由于主管道是东西走向的,所以影响到各油井的分管道总和的只有它们的纵坐标,所以我们可以不用考虑它们的横坐标.
假设y是主管道的y坐标(是个变量), \(a_i\) 表示第i个油田的y坐标(是个常量),为方便,假设 \(a_i\) 单调递增,那么各个分管道总和的公式为:
$ | a_1 - y | + | a_2 - y | + | a_3 - y | + ... + | a_n - y | $
如果大家还有初中数学数学的记忆的话,会发现这个式子就是在求到数轴上几个整点的距离之和最近的整点的坐标,显然这个坐标就是各个整点坐标的中位数.
考虑到部分同学或许已经忘记了这个规律,这里我们来证明一下.这个问题有很多方法证明,这里我们采用一个比较严谨的方法来证明.
通过简单证明,我们可以得到绝对值三角不等式: $ |a| + |b| \geq |a + b| $ .这个式子是可以推广到n个绝对值之和的形式(可通过数学归纳法或向量法证明,由于是纯数学知识,所以这里不证明了):
$ |a_1| + |a_2| + |a_3| + ... + |a_n| \geq |a_1 + a_2 + a_3 + ... + a_n| $ ,当且仅当各个数同号时等号成立.
我们前面根据题意得到的那个式子,正好是一组绝对值的和,所以我们可以考虑使用绝对值不等式.这边要注意的是,不等式右边不能得到一个含有变量的式子,这样可能会导致只能取得局部最值(忘了问问高中老师或者数院大佬,我这块学的也不是很清楚),所以我们需要对上面的式子进行变形,以便最后化出来的式子不含自变量y.
如何变形呢?我们只需要交换一半的绝对值中的被减数和减数即可.不过由于最后等号成立需要同号,所以不能随便交换(会导致不存能同号的y),一种(大概也是唯一一种)解决方法是,将 \(a_i\) 较大的一半的被减数和减数交换,这样便可以最终保证能够找到一个y使得等号成立(往下看,下面会给出一个不等式组,观察不等式组的形式你就明白了).
当n是偶数时,我们采用上面的方法对式子进行变形,可得:
$ | a_1 - y | + | a_2 - y | + | a_3 - y | + ... + | a_\frac{n}{2} - y| + | y - a_{\frac{n}{2} + 1}| + | y - a_{\frac{n}{2} + 2} | + | y - a_{\frac{n}{2} + 3} | + ...+ | y - a_n | \geq |a_1 + a_2 + a_3 + ... + a_\frac{n}{2} - a_{\frac{n}{2} + 1} - a_{\frac{n}{2} + 2} - a_{\frac{n}{2} + 3} - ... - a_n|$
当且仅当各个绝对值内数同号时(或全为0时)等号成立,即
\(\begin{cases} a_1 - y \leq 0\\ a_2 - y \leq 0\\ a_3 - y \leq 0\\ ...\\ a_\frac{n}{2} - y \leq 0\\ y - a_{\frac{n}{2} + 1} \leq 0\\ y - a_{\frac{n}{2} + 2} \leq 0\\ y - a_{\frac{n}{2} + 3} \leq 0\\ ...\\ y - a_n \leq 0 \end{cases}\)
可解得 \(a_\frac{n}{2} \leq y \leq a_{\frac{n}{2} + 1}\) ,这便是主管道应该修建位置的范围,在这个范围内任选一个整数(题目要求)均可让总长最小.(另一种全部 \(\geq0\) 是无解的,不信可以自己试试,也正是应为上面这个方程的形式,所以我们仅可采用这种交换的方式,其他方式都会导致y无解)
当n是奇数时,情况会稍微有所复杂,显然我们无法通过上面这样直接交换的方式消去y,因为无论如何都会多出来一个y,所以我们需要配凑形式来把式子数量变为偶数,这非常容易(但其实不好想到),我们将每个式子多写一遍,然后整体乘一个二分之一,这样就把绝对值的数量变为偶数了:
$ \frac{1}{2} \times (| a_1 - y | + | a_1 - y | + | a_2 - y | + | a_2 - y | + | a_3 - y | + | a_3 - y | + ... + | a_n - y | + | a_n - y |) $
然后我们继续采用上面的方法,交换较大的一半(为简便书写,下面的 \(\frac{n}{2}\) 默认向下取整.请注意交换是在 \(a_{\frac{n}{2} + 1}\) 处发生的,所以一个交换,而另一个不交换,最后就会被消掉.想不清楚可以在纸上写一下,看看一半是在哪个位置),可得:
$ \frac{1}{2} \times (| a_1 - y | + | a_1 - y | + | a_2 - y | + | a_2 - y | + | a_3 - y | + | a_3 - y | + ... | a_{\frac{n}{2} + 1} - y| + | y - a_{\frac{n}{2} + 1}| + | y - a_{\frac{n}{2} + 2}| + | y - a_{\frac{n}{2} + 2}| + ...+ | y - a_n | + | y - a_n |) \geq | a_1 + a_2 + a_3 + ... + a_{\frac{n}{2} -1} - a_{\frac{n}{2} + 2} - ... - a_n|$
当且仅当各个绝对值内数同号时(或全为0时)等号成立,即
\(\begin{cases} a_1 - y \leq 0\\ a_2 - y \leq 0\\ a_3 - y \leq 0\\ ...\\ a_{\frac{n}{2} + 1} - y \leq 0\\ y - a_{\frac{n}{2} + 1} \leq 0\\ y - a_{\frac{n}{2} + 2} \leq 0\\ y - a_{\frac{n}{2} + 3} \leq 0\\ ...\\ y - a_n \leq 0 \end{cases}\)
可解得 $ y = a_{\frac{n}{2} + 1} $ ,这便是主管道应该修建位置的位置,且显然这个位置也是个整数.(另一种全部 \(\geq0\) 是无解的,不信可以自己试试)
综合上面对奇数和偶数的讨论,我们可知:
由于偶数的中位数定义为: \(\frac{a_\frac{n}{2} + a_{\frac{n}{2} + 1}}{2}\) ,显然这个数是在 $ [a_\frac{n}{2} , a_{\frac{n}{2} + 1}] $ 内的,那么当n为偶数时,也可以让y取得这n个数的中位数(这道题要求修建位置为整数,如果 \(\frac{a_\frac{n}{2} + a_{\frac{n}{2} + 1}}{2}\) 不为整数,那么我们可以向下取整,反正只要在这个区间范围内即可).不过,有时候图方便,我们也可以不去求严格的中位数,毕竟只要在这个区间里就好了,我们直接取中间两个数中随便一个即可.
有了上面的结论,这题就很好办了,显然x坐标是没用的,我们直接读入各个y坐标,求出它们的中位数,然后计算出每一段距离即可.求中位数的方法非常简单,只需要将各个点的y坐标从小到大排序,然后取中间的数(偶数取中间的两个数,然后算平均值,向下取整)即可.
当然,这题没有要求我们输出主管道的位置,我们也可以直接利用我们前面不等式右边的形式,直接计算结果(当然这也是要排序的,因为我们前面分析那个式子的时候我们假设了 \(a_i\) 是从小到大的,我们交换的时候也是选择较大的一半交换的).
时间复杂度: \(O(NlogN)\) (排序时间)
空间复杂度: \(O(N)\) (计入输入数据存放空间)
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
// 输入各个点的y坐标
int *a = new int[n];
for (int i = 0; i < n; i++) {
int x; // x坐标用一个空的临时变量读掉
cin >> x >> a[i];
}
// 计算中位数
sort(a, a + n); // 先排序
int mid = a[n >> 1]; // 中位数就是排序后中间那个数(偶数时是中间两个数之一,也可以用.此处下标从0开始,所以不用加一.n >> 1等效于/2)
// 求和
int sum = 0;
for (int i = 0; i < n; i++) {
sum += abs(a[i] - mid);
}
cout << sum << "\n";
delete[] a;
return 0;
}
时间复杂度: \(O(NlogN)\) (排序时间)
空间复杂度: \(O(N)\) (计入输入数据存放空间)
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
// 输入各个点的y坐标
int *a = new int[n];
for (int i = 0; i < n; i++) {
int x; // x坐标用一个空的临时变量读掉
cin >> x >> a[i];
}
// 计算最小值
sort(a, a + n); // 先排序
int res = 0;
for (int i = 0; i < (n >> 1); i++) { // 利用双指针技巧(另一个指针是n - i - 1,不用单独维护),使得求奇数时正好会跳掉中间的那个点,不用分类讨论
res += a[i] - a[n - i - 1]; // 头和尾一起算进去
}
cout << abs(res) << "\n"; // 别忘了取绝对值
delete[] a;
return 0;
}
"正是我们每天反复做的事情,最终造就了我们,优秀不是一种行为,而是一种习惯" ---亚里士多德
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
由于fast-stemmer的问题,我很难安装我想要的任何rubygem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有, 也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
文章目录git常用命令(简介,详细参数往下看)Git提交代码步骤gitpullgitstatusgitaddgitcommitgitpushgit代码冲突合并问题方法一:放弃本地代码方法二:合并代码常用命令以及详细参数gitadd将文件添加到仓库:gitdiff比较文件异同gitlog查看历史记录gitreset代码回滚版本库相关操作远程仓库相关操作分支相关操作创建分支查看分支:gitbranch合并分支:gitmerge删除分支:gitbranch-ddev查看分支合并图:gitlog–graph–pretty=oneline–abbrev-commit撤消某次提交git用户名密码相关配置g