链接:https://ac.nowcoder.com/acm/contest/5403/A
来源:牛客网
题目描述
张经理的公司的办公室长达100000米,从最左端开始每间隔1米都有一个工位(从第1米开始有工位),位于第i米的工位称为i号工位,且这些工位都在一条水平线上。他有n个员工,每个员工分别位于xi号工位上(不同员工可能位于同一个工位)。
现在张经理想把员工聚集在某两个工位上,他有q套方案(每套方案包含两个工位号,两个工位号可能相同),他想知道对于每套方案,所有员工都到达两个工位中的某一个所需走的最短路径之和是多少。
中心思想
桶排序,前缀和处理,二分法
题目思路
【桶排序输入】
在题目中采用桶排序方式对工号进行输入。
//n为员工个数 //site[i]记录工位为i号的员工个数 for(int i=0;i<n;i++) { int temp; scanf("%d",&temp); site[temp]++; }
【前缀和处理】
设置两个前缀和数组sum1和sum2。
其中,sum1[i]存放工位小于i的员工的工位号和;sum2[i]存放工位号小于i的员工数量。
for(int i=2;i<=MAXN+1;i++) { sum1[i]=sum1[i-1]+site[i-1]*(i-1); sum2[i]=sum2[i-1]+site[i-1]; }
【二分思想】
取所选工位号的中间值mid=(a+b)/2,其中,工位号小于等于mid的向a移动,大于mid的向b移动。
选中1号(a)和4号(b)作为目标工位,则mid为2。
以下图为例:
所有员工被分为两大部分:向a移动的部分和向b移动的部分。
对于向a移动的部分,分为a左边员工的移动和a右边员工的移动:
a左边:ans = sum2[a] * ( a - sum1[a]/sum2[a] ) = sum2[a] * a - sum1[a]
a右边:ans = ( sum2[mid+1] - sum2[a+1] ) * (( sum1[mid+1] - sum1[a+1] )/( sum2[mid+1] - sum2[a+1] ) - a ) = ( sum1[mid+1] - sum1[a+1] ) - ( sum2[mid+1] - sum2[a+1] ) * a
对于向b移动的部分同理可得,不再赘述。
//a左边(1~a) ans+=a*sum2[a]-sum1[a]; //a右边(a~mid) ans+=(sum1[mid+1]-sum1[a+1])-(sum2[mid+1]-sum2[a+1])*a; //b左边(mid+1~b) ans+=(sum2[b]-sum2[mid+1])*b-(sum1[b]-sum1[mid+1]); //b右边(b~MAX) ans+=sum1[MAXN+1]-sum1[b+1]-(sum2[MAXN+1]-sum2[b+1])*b;
完整代码如下:
#include<stdio.h> #define MAXN 100000 int site[MAXN+1]={0};//工位号与当前下标相同的员工数 int sum1[MAXN+1]={0};//小于当前下标的工位号之和 int sum2[MAXN+1]={0};//工位号小于当前下标的人数 int main() { int n,q; scanf("%d%d",&n,&q); //桶排序方式输入 for(int i=0;i<n;i++) { int temp; scanf("%d",&temp); site[temp]++; } //前缀和处理 for(int i=2;i<=MAXN+1;i++) { sum1[i]=sum1[i-1]+site[i-1]*(i-1); sum2[i]=sum2[i-1]+site[i-1]; } for(int i=1;i<=q;i++) { int a,b; scanf("%d%d",&a,&b); //二分法,所选工位的中间值 int mid=(a+b)/2; int ans=0; //保证a<=b if(a>b) { int t=a; a=b; b=t; } //a左边(1~a) ans+=a*sum2[a]-sum1[a]; //a右边(a~mid) ans+=(sum1[mid+1]-sum1[a+1])-(sum2[mid+1]-sum2[a+1])*a; //b左边(mid+1~b) ans+=(sum2[b]-sum2[mid+1])*b-(sum1[b]-sum1[mid+1]); //b右边(b~MAX) ans+=sum1[MAXN+1]-sum1[b+1]-(sum2[MAXN+1]-sum2[b+1])*b; printf("%d\n",ans); } return 0; }
算法复杂度为O(q)。
个人错误
本题目看起来思路简单,但是为了满足题目的时间要求,不能仅利用单纯的遍历循环来实现。