[APIO2015]八邻旁之桥
XXI.[APIO2015]八邻旁之桥
首先先忽略所有在同侧的人,考虑异侧的人。
则明显,如果我们只在位置修一座桥,则一个从某侧的到另一侧的的人,其一共要走的距离就是
(忽略了桥长,因为桥长可以被统一计算)
于是我们发现,此时和是独立的。于是问题就转成了数轴上有很多点,要求一个点 到所有点的距离和最小。
通过逐步调整法,我们可以发现即为所有点的中位数。(因为点的数量是偶数,所以会有两个中位数,此时选择任何一个都是可以的)
进一步拆开绝对值符号之后,会发现是。
现在有两座桥了。我们会发现,假如我们对所有人按照排序,则一定是前一半的人走左侧的桥,后一半人走右侧的桥。这可以通过画出图来证明:两端都在左侧桥左方的人,或是都在右侧桥右方的人,显然走相应的桥最优;两端各在两侧桥两边的人,显然走任何一座桥都是可以的;唯独两端在两侧桥之间的人,画出图来,会发现走离其更近的桥更优,而比较就是按比较的。
于是我们现在就可以枚举这个断点,两边就分别转成了一座桥的问题。于是我们现在就要对于每个前缀和后缀,求出其中,并将两边拼在一起。
如何求出呢?
平衡树
那就太可怕了。直接使用两个堆即可,其中一个是大根堆,维护前一半数;一个是小根堆,维护后一半数。当加入一个人时,先把其和全部插入大根堆,然后再平衡两个堆的大小即可。假如发现平衡过后,大根堆的顶大于小根堆的顶,就交换堆顶元素即可。
时间复杂度。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,r;
pair<int,int>p[100100];
vector<int>v[2];
char s[4];
ll all,mn=0x3f3f3f3f3f3f3f3f,pre[100100],suf[100100],PRE,SUF;
priority_queue<int>P,Q;//P:greater heap for smaller part; Q:smaller heap for greater part
int main(){
scanf("%d%d",&m,&r);
for(int i=1,x,y;i<=r;i++){
scanf("%s%d",s,&x);
scanf("%s%d",s+1,&y);
if(s[0]==s[1])all+=abs(x-y);
else p[++n]=make_pair(x,y);
}
all+=n;
sort(p+1,p+n+1,[](pair<int,int>u,pair<int,int>v){return u.first+u.second<v.first+v.second;});
while(!P.empty())P.pop();while(!Q.empty())Q.pop();PRE=SUF=0;
for(int i=1;i<=n;i++){
PRE+=p[i].first,PRE+=p[i].second;
P.push(p[i].first),P.push(p[i].second);
while(P.size()!=Q.size())PRE-=P.top(),SUF+=P.top(),Q.push(-P.top()),P.pop();
while(P.top()>-Q.top()){
int x=P.top(),y=-Q.top();
PRE-=x,PRE+=y;
SUF+=x,SUF-=y;
P.pop(),Q.pop();
P.push(y),Q.push(-x);
}
pre[i]=SUF-PRE;
}
while(!P.empty())P.pop();while(!Q.empty())Q.pop();PRE=SUF=0;
for(int i=n;i>=1;i--){
PRE+=p[i].first,PRE+=p[i].second;
P.push(p[i].first),P.push(p[i].second);
while(P.size()!=Q.size())PRE-=P.top(),SUF+=P.top(),Q.push(-P.top()),P.pop();
while(P.top()>-Q.top()){
int x=P.top(),y=-Q.top();
PRE-=x,PRE+=y;
SUF+=x,SUF-=y;
P.pop(),Q.pop();
P.push(y),Q.push(-x);
}
suf[i]=SUF-PRE;
}
if(m==1)mn=min(pre[n],suf[1]);
else for(int i=0;i<=n;i++)mn=min(mn,pre[i]+suf[i+1]);
printf("%lld\n",all+mn);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?