• 【HDU 4311】Meeting point-1(前缀和求曼哈顿距离和)


    题目链接

    正经解法:

    给定n个点的坐标,找一个点,到其他点的曼哈顿距离之和最小。
    n可以是100000。
    大概要一个O(nlogn)的算法。
    算曼哈顿距离可以把x和y分开计算排好序后计算前缀和就可以在O(1)时间内判断一个点到其他点的距离。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 100005
    int t,n;
    ll ans,sum[N],sx[N],sy[N];
    struct p
    {
        int i;
        ll x,y;
    } a[N];
    int cmpx(p a,p b)
    {
        return a.x<b.x;
    }
    int cmpy(p a,p b)
    {
        return a.y<b.y;
    }
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            sx[0]=sy[0]=0;
            scanf("%d",&n);
            for(int i=1; i<=n; i++)
            {
                scanf("%lld%lld",&a[i].x,&a[i].y);
                a[i].i=i;
            }
            sort(a+1,a+n+1,cmpx);
            for(int i=1; i<=n; i++)
                sx[i]=sx[i-1]+a[i].x;
            for(int i=1;i<=n;i++)
                sum[a[i].i]=a[i].x*(i-1)-sx[i-1]+sx[n]-sx[i]-a[i].x*(n-i);
            sort(a+1,a+n+1,cmpy);
            for(int i=1; i<=n; i++)
                sy[i]=sy[i-1]+a[i].y;
            for(int i=1; i<=n; i++)
            {
                sum[a[i].i]+=a[i].y*(i-1)-sy[i-1]+sy[n]-sy[i]-a[i].y*(n-i);
                ans=(i==1)?sum[a[1].i]:min(ans,sum[a[i].i]);
            }
            printf("%lld
    ",ans);
        }
    }

    缩小范围法:

    另外一种做法,当时我就是这么想的,但是后来没敢交,觉得还是会wa。
    因为本身就不是很可靠。
    按x排序后,取中间x的附近点来计算(经过我多次提交,发现这个范围不能小于±220,这就是难点所在了,为什么是250左右,赛场上全凭直觉取值)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    struct p{ll x,y;}a[100005];
    ll ABS(ll a){
        if(a<0)a=-a;
        return a;
    }
    ll dis(p a, p b){
        return ABS(a.x-b.x)+ABS(a.y-b.y);
    }
    int cmp(p a,p b){
        return a.x<b.x;
    }
    int main(){
        int t,n,s,e;
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
                scanf("%lld%lld",&a[i].x,&a[i].y);
            sort(a+1,a+1+n,cmp);
            s=n/2-223;
            e=n/2+223;
            if(s<1)s=1;
            if(e>n)e=n;
            ll ans=1LL<<60;
            for(int z=s;z<=e;z++){
                ll s=0;
                for(int i=1;i<=n;i++)
                    s+=dis(a[z],a[i]);
                ans=min(s,ans);
            }
            printf("%lld
    ",ans);
        }
    }

      

  • 相关阅读:
    dpkg 删除 百度网盘 程序
    ubuntu 安装go
    解决 swap file “*.swp”already exists!问题
    ROS Topic 常用指令
    正交概念
    vim 永久显示行号 & 临时显示行号
    awk、grep、sed
    Keil中使用Astyel进行C语言的格式化
    红黑树学习
    802.11 对于multicast 和 broadcast的处理
  • 原文地址:https://www.cnblogs.com/flipped/p/5697636.html
Copyright © 2020-2023  润新知