洛谷 P3819 松江1843路

简介: 题目描述 涞坊路是一条长L米的道路,道路上的坐标范围从0到L,路上有N座房子,第i座房子建在坐标为x[i]的地方,其中住了r[i]人。 松江1843路公交车要在这条路上建一个公交站,市政府希望让最多的人得到方便,因此希望所有的每一个的居民,从家到车站的距离的总和最短。

题目描述

涞坊路是一条长L米的道路,道路上的坐标范围从0到L,路上有N座房子,第i座房子建在坐标为x[i]的地方,其中住了r[i]人。

松江1843路公交车要在这条路上建一个公交站,市政府希望让最多的人得到方便,因此希望所有的每一个的居民,从家到车站的距离的总和最短。

公交站应该建在哪里呢?

输入输出格式

输入格式:

 

第一行输入L、N。

接下来N行,每行两个整数x[i]和r[i]。

 

输出格式:

 

一个整数,最小的每个人从家到车站的距离的总和。

 

输入输出样例

输入样例#1:
100 3
20 3
50 2
70 1
输出样例#1:
110

输入样例#2:
100 2
0 1
100 10
输出样例#2:
100
输入样例#3:
10000000000 5
3282894320 391
4394338332 929
6932893249 181
7823822843 440
9322388365 623
输出样例#3:
5473201404068

说明

样例解释1

当建在坐标40的时候,所有人距离车站的距离总和为 |20−40|×3+|50−40|×2+|70−40|×1=110。

数据范围和约定

对于10%的数据,1≤N≤50,R[i]=1。

对于30%的数据,1≤N≤100,R[i]≤10,1≤L≤1000。

对于70%的数据,1≤N≤1000,R[i]≤100,1≤L≤10^6。

对于全部数据,1≤L≤10^10,1≤N≤10^5,0≤x[i]≤L,1≤r[i]≤1000

吐槽

  好久没做在洛谷被标成“普及+/提高”难度的题了,这题难度被标高了……

  cmath里的abs简直就是一个大坑,当传过去的参数为long long型的时,返回值依然是int!!!

  因为这个我WA90分,整整两次!

  对long long取绝对值要algorithm里的std::abs才行,再或者就手写……

解题思路

中位数的思路

  题目原型是输油管道,在这里,出题人说洛谷7月月赛题目都是改编题果然不假。

  把每个人所在的位置记录下来,排成一个数列,那么公交站的位置就是这个数列的中位数所在位置。为什么是中位数呢?可以参考输油管道这题“深海鱼的眼泪”的题解.

我把他的题解改了一点——

  如果只有一个人,那么显然是越近越好。如果有两个人,那么显然是有以下三种情况:

    1.两个人都在公交站左边,那么这个时候的两个人到公交站的长度和肯定大于两个人的坐标之差。

    2.两个人都在公交站右边,和情况1是一样的

    3.两个人,一个在公交站右边,一个在公交站左边,那么两个人到公交车站的长度和就等于两个人的坐标之差。显然情况三是所要的路径和最短的设计情况。就是当公交站在两个人之间的任意位置时,人到公交车站长度之和都等于两个人的坐标之差,是最短的长度。

  那么将这个结论推广,当有n个人的时候——

    1.n是偶数 只要这n个人分布在公交站的两边,每边n/2个,那么就是距离之和最小的。

    2.n是奇数,只要将这n个人中,坐标最中间的(也就是中位数的那个)井不算,其余的偶数个人分布在公交站的两侧,这个时候移动公交站,那么这n个人到公交车站长度之和就决定于那个没有算的人了,因为其余的井的距离之和是固定了的,这个时候只要公交站最接近中间那个人就好了。

  也就是说,公交车站的位置就是最中间的那个人(或中间的区间)。

  将各个人的坐标排序,再取 n/2+1 的位置,即最中间的位置。最后统计答案即可。

三分的思路

  设f(x)为公交站设在x处时所有人到公交站距离之和,那么有可能f(x)在[1,L]上很有可能只有一个极小值(我不会证,但这个思路可以通过所有数据点,耗时为上面那个思路的一半),那个极小值就是答案。求那个极小值就能用三分法了。这个思路来自洛谷讨论区huxulin,下面的代码也是他的。

源代码

中位数思路的代码

#include<algorithm>
#include<cstdio>

struct house{
    long long x,num;
    bool operator < (const house & a) const{
        return x<a.x;
    }
}h[100010];
long long n,sum=0;
int main()
{
    scanf("%lld",&n);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld",&h[i].x,&h[i].num),sum+=h[i].num;
    std::sort(h+1,h+1+n);
    long long s=0,mid=(sum>>1)+1,pos;
    for(int i=1;i<=n;i++)
    {
        s+=h[i].num;
        if(s>=mid)
        {
            pos=h[i].x;
            break;
        }
    }
    long long ans=0;
    for(int i=1;i<=n;i++)
        ans+=std::abs(h[i].x-pos)*h[i].num;
    printf("%lld",ans);
    return 0;
}

三分的代码

#include <cstdio>
#include <algorithm>

typedef long long LL;

static const int maxm = 2e6 + 10;
static const LL INF = 1LL << 62;

LL r[maxm],x[maxm],A[maxm];
LL L,ans,mind = INF;
LL n;

LL abs(LL x){
    return x > 0 ? x : -x;
}

LL f(LL D){
    LL ret = 0;
    for(LL i = 1;i <= n;i++) ret += abs(D * r[i] - x[i] * r[i]);
    return ret;
}

int main(){
    scanf("%lld%lld",&L,&n);
    for(LL i = 1;i <= n;i++) scanf("%lld%lld",&x[i],&r[i]);

    LL l = 0,r = L;

    while(l <= r){
        LL mid = (l + r) >> 1;
        LL mmid = (mid + r) >> 1;
        if(f(mid) < f(mmid)) ans = mid,r = mmid - 1;
        else ans = mmid,l = mid + 1;
    }

    for(LL i = ans - 100;i <= ans + 100;i++)
        mind = std :: min(f(i),mind);

    printf("%lld\n",mind);
    
    return 0;
}

 

目录
相关文章
|
C# Android开发 虚拟化
C# 一分钟浅谈:MAUI 跨平台移动应用开发
.NET MAUI 是 Microsoft 推出的跨平台框架,支持 Windows、macOS、iOS 和 Android。本文从基础概念入手,探讨 MAUI 的常见问题、易错点及解决方案,并通过代码示例详细说明。涵盖平台特定代码、XAML 语法、数据绑定、性能优化和调试技巧等内容,帮助开发者更好地掌握 .NET MAUI。
1213 55
|
人工智能 边缘计算 运维
AI 时代下,操作系统的进化与重构
随着人工智能(AI)的迅猛发展,操作系统面临着前所未有的挑战和机遇。在这个新时代,操作系统需要进行深刻的进化与重构,以适应AI技术的广泛应用和不断变化的需求。
649 5
|
11月前
|
机器学习/深度学习 人工智能 运维
CodeFuse团队2024年10篇论文总结
CodeFuse 是蚂蚁集团开发的多语言代码大型语言模型(LLM),基于海量高质量代码数据和多任务微调技术,已在内部研发人员的编码、测试、运维等场景中广泛应用。2024年,CodeFuse 在国际顶会如ICSE、ICDE、KDD等发表多篇论文,涵盖CodeLLM、机器学习、AI等领域,并开源多个自研大模型,总下载量近200万。项目持续迭代,欢迎贡献和建议。
491 11
|
10月前
|
人工智能 小程序 数据挖掘
2025年企业CRM选型指南:销售易、金蝶、纷享销客对比
销售易、金蝶和纷享销客是国内知名的CRM解决方案,各自具备独特优势。销售易功能全面,涵盖销售、客户、营销管理及AI赋能,适合中大型企业;金蝶与ERP无缝集成,财务管理强大,适合传统企业;纷享销客连接能力强,用户体验佳,性价比高,适合中小企业。本文从功能、体验、价格、评价及适用场景对比三者,助力企业选择合适的CRM系统,推动数字化转型。
|
Java
Java强制类型转换需要注意的点
在 Java 中,强制类型转换(显式类型转换)用于将一种数据类型转换为另一种。然而,这一过程需谨慎处理以避免以下问题:数据丢失,尤其是在从大范围类型转换到小范围类型时;类型不兼容,如 `String` 无法直接转换为 `int`;对象类型转换时应确认实际类型与目标类型兼容,可借助 `instanceof` 运算符;处理基本类型与包装类之间的自动装箱和拆箱时需注意 `null` 值;浮点数转整数时会截断小数部分;字符转整数则得到 Unicode 值。充分理解这些注意事项有助于避免运行时错误和数据不一致。
433 16
|
人工智能 运维 安全
阿里云飞天企业版“智算升级”,为政企打造AI时代最开放的云
阿里云正式发布飞天智算—飞天企业版V3.18,为政企客户打造AI时代最开放的云。此次升级,飞天企业版将智算能力深度融入云平台,实现“一云多算”,满足政企客户对云平台“云+AI”协同发展需求,为AI技术大规模在政企领域应用做好准备。
1136 11
|
传感器 机器人 测试技术
Nvidia Isaac Sim组装机器人和添加传感器 入门教程 2024(5)
本文是Nvidia Isaac Sim组装机器人和添加传感器的入门教程,介绍了在Isaac Sim中组装一个简单的两轮差速机器人的步骤,包括创建3D模型部件、组建关节、创建关节树、添加关节驱动,以及如何添加和配置传感器,特别是相机传感器。
2074 0
|
C++
C++ PCL 计算多个RT矩阵变换后的变换矩阵
C++ PCL 计算多个RT矩阵变换后的变换矩阵
222 0
|
算法 计算机视觉
OpenCV中使用加速鲁棒特征检测SURF与图像降噪讲解与实战(附源码)
OpenCV中使用加速鲁棒特征检测SURF与图像降噪讲解与实战(附源码)
264 0
|
Linux 编译器 Go
Linux内核学习(四):Bootloader的特种兵-Uboot(二)
Linux内核学习(四):Bootloader的特种兵-Uboot(二)
980 0