【HDU4312】Meeting point-2(切比雪夫距离和曼哈顿距离的转化+前缀和后缀和去绝对值)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4312

必备知识:https://www.cnblogs.com/zwfymqz/p/8253530.html

二维坐标轴上两点:A(x1,y1) B(x2,y2)

切比雪夫距离:disq = max(|x1-x2|, |y1-y2|)

曼哈顿距离:dism = |x1-x2|+|y1-y2|

切比雪夫距离--->曼哈顿距离:(x,y)变换为(  ,  )

证明:A(0,0) B(x,y)  C(  ,  )

AB之间的切比雪夫距离disq = max(|x|,|y|) ,AC之间的曼哈顿距离dism = |  |  +| |

(1)当x>0且y>0时 :dism = max(x,y),disq = max(x,y)

(2)当x<0且y<0时:dism = max(|x|,|y|), disq = max(|x|, |y|)

当x异号时,dism和disq也是等价的。(我懒得打字了。。)

曼哈顿距离--->切比雪夫距离:(x,y)变换为(x+y, x-y)

证明方法同上,分情况讨论一下就好了。

 

题目:


给出二维坐标轴上的一些点,要找到一个点,使其他点到它的切比雪夫距离之和最小,求最小的距离和

 

解题思路:


因为切比雪夫距离求解的时候是max(||,||)的形式,不仅要消除绝对值的影响,而且还要去个max,求起来比较麻烦。

将切比雪夫距离转化为曼哈顿距离,这样就只需要消除绝对值的影响了。

将输出的点先按照x值从小到大排序,记录x的前缀和和后缀和,为了消除绝对值的影响,每次求解曼哈顿距离是都让排名靠后的数-排名靠前的数。这样就可以求出来某个点和其他点的x值距离之和。

比如:x排完序为:-4,-3,-2,0,4,5,(下标从1开始)当求解其他点到x值第三小的这个点(x=-2这个点)时,

dism = |-2-(-4)| + |-2-(-3)|     +  |0-(-2)| + |4-(-2)| + |5-(-2)| 

      = (-2)* 2  - ((-4)+(-3))  +    ( 0 + 4 + 5 )- (-2) *  3

      =  (-2)* ( i - 2) - pre_sum[ i - 1 ]    +   suf_sum[ i + 1 ] - (-2)* ( n  -  i )

再把点按照y值从小到大排序,用同样的方法求出某个点和其他点的y值距离之和

最终求距其他点x值和+y值和的最小值即可。

 

ac代码:


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
struct node
{
    ll p[2];
    int pos;
} a[maxn];

int n;
ll sum[maxn][2];
ll ans[maxn];

void solve(int x)
{
    for(int i = 1;i<= n;i++)
        sum[i][0] = a[i].p[x]+sum[i-1][0];//前缀和
    for(int i = n;i>= 1;i--)
        sum[i][1] = a[i].p[x]+sum[i+1][1];//后缀和

    for(int i = 1;i<= n;i++)
        // 前面到ta的x/y绝对值距离之和 + 后面的到它的绝对值距离之和
        ans[a[i].pos]+= a[i].p[x]*(i-1)-sum[i-1][0] + sum[i+1][1]-a[i].p[x]*(n-i);
}
bool cmp1(node x,node y)
{
    return x.p[0]< y.p[0];
}
bool cmp2(node x,node y)
{
    return x.p[1]< y.p[1];
}

int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    int t;
    scanf("%d", &t);
    while(t--)
    {
        memset(sum, 0 ,sizeof(sum));
        scanf("%d",&n);
        for(int i = 1;i<= n;i++)
        {
            ll x,y;
            scanf("%lld %lld",&x,&y);
            a[i].p[0] = x+y;
            a[i].p[1] = x-y;
            a[i].pos = i;
            ans[i] = 0;
        }

        sort(a+1,a+n+1,cmp1);
        solve(0);
        sort(a+1,a+n+1,cmp2);
        solve(1);

        ll m = ans[1];
        for(int i = 2;i<= n;i++)
            m = min(m,ans[i]);

        printf("%lld\n",m/2);
    }

    return 0;
}

 

全部评论

相关推荐

01-28 16:12
中南大学 Java
几年前还没有chatgpt的时候,刷题真的是很痛苦。刷不出来只能看题解,题解有几个问题:第一个是每次看的写题解的人都不一样,很难有一个统一的思路;第二个也是最重要的是,题解只提供了作者自己的思路,但是没有办法告诉你你的思路哪里错了。其实很少有错误的思路,我只是需要被引导到正确的思路上面去。所以传统题解学习起来非常困难,每次做不出来难受,找题解更难受。但是现在chatgpt能做很多!它可以这样帮助你&nbsp;-1.&nbsp;可以直接按照你喜欢的语言生成各种解法的题解和分析复杂度。2.&nbsp;把题和你写的代码都发给它,它可以告诉你&nbsp;你的思路到底哪里有问题。有时候我发现我和题解非常接近,只是有一点点🤏想错了。只要改这一点点就是最优解。信心倍增。3.&nbsp;如果遇到不懂的题解可以一行一行询问为什么要这样写,chatgpt不会嫌你烦。有时候我觉得自己的range写错了,其实那样写也没错,只是chat老师的题解有一点优化,这个它都会讲清楚。4.&nbsp;它可以帮你找可以用同类型解法来做的题。然后它可以保持解法思路不变,用一个思路爽刷一个类型的题。如果题目之间思路又有变化,它会告诉你只有哪里变了,其他的地方还是老思路。5.&nbsp;它也可以直接帮你总结模板,易错点。经过chat老师的指导,我最大的改变是敢刷题了。之前刷题需要先找某一个人写的算法题repo,然后跟着某一个人他的思路刷他给的几个题。如果想写别的题,套用思路失败了,没有他的题解,也不知道到底哪里错了;看别人的题解,思路又乱了。这个问题在二分查找和dp类型的题里面特别常见。但是现在有chat老师,他会针对我的代码告诉我我哪里想错了,应该怎么做;还按照我写代码的习惯帮我总结了一套属于我的刷题模板。每天写题全是正反馈!
明天不下雨了:那我建议可以用 chatgpt atlas 或者 dia 去刷,也可以用 chrome 加个 ai 插件去刷 左边刷题右边 chat 效果很好
AI时代的工作 VS 传...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务