火车站选址-字节跳动笔试

                                           火车站选址

这道题目是字节跳动2020.9.20的一道题目

题目描述:

A市计划新建一个火车站方便市民出行。

这里的道路十分规整,市民从位置(x1,y1)到位置(x2,y2)的路程为|x1-x2|+|y1-y2|

经过前期考察,初步选定了M个可以建造火车站的位置。

为了尽可能节省市民到达火车站的时间,市长希望新建的车站离每位市民的总路程尽可能的小。

请帮市长选出最适合新建火车站的位置。

输入描述:

第一行有两个整数N,M;分别表示市民的人数和可以建设火车站的位置

后面N行,每行2个整数x_i,y_i,表示第i位市民的居住位置在(x_i,y_i)

后面M行,每行2个整数p_i,q_i,表示第i个火车候站候选位置在(p_i,q_i)

1 <= N <= 100000

1 <= M <= 100000

-10000000 <= x_i , y_i , p_i , q_i <= 10000000

输出描述:

两个整数 p_i , q_i 表示最合适新建火车站的位置,若有多个答案,输出原始数据中第一个出现的

样例输入:

4 3
-1 -1
-1 1
1 -1
1 1
3 2
1 0
0 0

样例输出:

1 0

题目解析:

首先这道题上来看数据n,m都是1e5 ,x,y,p,q分别1e7,显然我们不能用暴力去做

我们就想到给原有的x_i,y_i,在实际运算中其实是独立的,需要去求的是最后的和,所以我们可以将x和y分成两个数组 并排序。那么 我们得到了有序的x,y后 如果给我们一组p,q,如何去计算 总共的花费呢?

此时想到前缀和

对于p来说,我们找到p在x里比p小的位置L1和比p大的位置L2,那么比p小的贡献就是(L1*p)-sum[L1];

sum就是前缀和,比p大的贡献就是sum[n]-sum[L2]-(n-L2)*p;

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;

int xx[100005],yy[10005];
long long sumx[100005],sumy[100005];
int x,y;
int main()
{
    long long minx=9223372036854775807;
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        scanf("%d%d",&x,&y);
        xx[i]=x;
        yy[i]=y;
    }
    sort(xx,xx+n);
    sort(yy,yy+n);
    sumx[0]=xx[0];
    sumy[0]=yy[0];
    for(int i=1;i<n;i++){
        sumx[i]=sumx[i-1]+xx[i];
        sumy[i]=sumy[i-1]+yy[i];
    }
    int ansx,ansy;
    long long now;
    for(int i=0;i<m;i++){
        scanf("%d%d",&x,&y);
        now=0;
        int ll;
        ll=lower_bound(xx,xx+n,x)-xx;
        now+=(ll)*x-sumx[ll-1];
        ll=lower_bound(yy,yy+n,y)-yy;
        now+=(ll)*y-sumy[ll-1];
        ll=upper_bound(xx,xx+n,x)-xx;
        if(ll<n)now+=(sumx[n-1]-sumx[ll-1])-(n-ll)*x;
        ll=upper_bound(yy,yy+n,y)-yy;
        if(ll<n)now+=(sumy[n-1]-sumy[ll-1])-(n-ll)*y;
        if(now<minx){
            ansx=x;
            ansy=y;
            minx=now;
        }
    }
    cout<<ansx<<' '<<ansy<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36909245/article/details/108699317