UESTC 929 Post office【前缀和+贪心】

本文介绍了一个经典的邮局选址问题,即如何在一个包含多个村庄的区间内选择最优位置建造邮局,使得所有村庄到该邮局的距离之和最小。文章详细阐述了解决方案,并提供了高效的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Post office

Problem:698
Time Limit:1000ms
Memory Limit:65536K

Description

There are N(N<=1000) villages along a straight road, numbered from 1 to N for simplicity. We know exactly the position of every one (noted pos[i],pos[i] is positive integer and pos[i]<=10^8). The local authority wants to build a post office for the people living in the range i to j(inclusive). He wants to make the sum of |pos[k]-position_of_postoffice| (i<=k<=j) is minimum. 

Input

  For each test case, the first line is n. Then n integer, representing the position of every village and in acending order. Then a integer q (q<=200000), representing the queries. Following q lines, every line consists of two integers i and j. the input file is end with EOF. Total number of test case is no more than 10.
  Be careful, the position of two villages may be the same.

Output

  For every query of each test case, you tell the minimum sum.

Sample Input

3
1 2 3
2
1 3
2 3
0

Sample Output

2
1

Hint

  Huge input,"scanf"is recommend.
题目大意:


给你N个村庄的坐标,一共有Q个查询,每个查询想要在区间【i,j】之内的某个村庄建立邮局,其他村庄的村民都过来到这个点来邮寄,希望其他各个点到这个邮局的距离之和最小,问这个最小的和。

每个查询都是独立的。


思路:

很显然,我们在区间【i,j】之内建立一个邮局,我们希望其他各个点到这个点的距离之和最小,那么这个邮局需要尽可能的在中间部位建成。


①当区间内点的个数为奇数的时候,建立邮局就在中间点。

②当区间内点的个数为偶数的时候,建立邮局在中间的两个点之中的任意一个点,取最小值。


那么我们如果暴力做的话,时间复杂度会达到O(qn);

所以我们这里再维护一个前缀和,就能做到O(q)了;


Ac代码:

#include <bits/stdc++.h>
typedef long long int ll;
using namespace std;
int n;
ll sum[150000];
ll a[150000];
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=0;i<n;i++)scanf("%lld",&a[i]);
        for(int i=0;i<n;i++)
        {
            if(i==0)sum[i]=a[i];
            else sum[i]=sum[i-1]+a[i];
        }
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            x--;
            y--;
            if((y-x+1)%2==1)
            {
                int mid=(x+y)/2;
                ll num=(y-x+1)/2;
                ll output=a[mid]*num-(sum[mid-1]-sum[x-1]);
                output+=(sum[y]-sum[mid])-a[mid]*num;
                printf("%lld\n",output);
            }
            else
            {
                int mid=(x+y)/2;
                ll num=(y-x+1)/2-1;
                ll output=a[mid]*num-(sum[mid-1]-sum[x-1]);
                output+=(sum[y]-sum[mid])-a[mid]*(num+1);
                mid=(x+y)/2+1;
                num=(y-x+1)/2;


                ll output2=a[mid]*num-(sum[mid-1]-sum[x-1]);
                output2+=(sum[y]-sum[mid])-a[mid]*(num-1);
                printf("%lld\n",min(output,output2));
            }
        }
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值