题目描述
在一个镇上有n个村子,每个村子住着数量不等的居民。这些村子可以看做是排列在一条直线上的若干个整数点。现在镇长要在村子里建一个邮局。请问将邮局建在哪一个村子,可以使得所有居民走到邮局的距离和最小。
输入格式
第一行一个整数n,表示有n个村子。
接下来有n行,每行两个数,表示第i个村子的坐标和居民数。保证所有村子的坐标都是正整数。
输出格式
输出两个数,第一个数表示建邮局的村子的坐标,第二个数表示最小的距离和。如何有多个村子适合建邮局,输出坐标最小的那个。输出结果中间有1个空格间隔。
样例
样例输入
4
1 10
5 20
3 5
10 7
样例输出
5 85
做法:
设在
x
x
x位置建邮局,答案就是
∑
i
=
1
n
∣
x
−
a
i
∣
\sum_{i=1}^{n} |x-a_{i}|
∑i=1n∣x−ai∣,然后分类讨论去绝对值符号,具体实现就是先排序,再用前缀和对每个位置都算一次答案,最后取
m
i
n
min
min
代码:
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000005
#define int long long
struct node {
int x, cnt;
node(int a = 0, int b = 0){x = a, cnt = b;}
bool operator <(const node &t) const {
return x < t.x;
}
};
node a[MAXN];
int precnt[MAXN], lascnt[MAXN];
int preans[MAXN], lasans[MAXN];
signed main()
{
int n;
scanf("%lld", &n);
for(int i = 1; i <= n; i++)
scanf("%lld %lld", &a[i].x, &a[i].cnt);
sort(a + 1, a + n + 1);
// puts("-------------------");
// for(int i = 1; i <= n; i++)
// {
// printf("%d %d\n", a[i].x, a[i].cnt);
// }
// puts("-------------------");
for(int i = 1; i <= n; i++)
precnt[i] = precnt[i - 1] + a[i].cnt;
for(int i = n; i >= 1; i--)
lascnt[i] = lascnt[i + 1] + a[i].cnt;
for(int i = 2; i <= n; i++)
preans[i] += preans[i - 1] + precnt[i - 1] * (a[i].x - a[i - 1].x);
for(int i = n - 1; i >= 1; i--)
lasans[i] += lasans[i + 1] + lascnt[i + 1] * (a[i + 1].x - a[i].x);
// for(int i = 1; i <= n; i++)
// {
// printf("%d %d\n", precnt[i], lascnt[i]);
// }
// puts("-------------------");
// for(int i = 1; i <= n; i++)
// {
// printf("%d %d\n", preans[i], lasans[i]);
// }
// puts("-------------------");
int x, ans = 0x3f3f3f3f3f3f3f3f;
for(int i = 1; i <= n; i++)
{
if(preans[i] + lasans[i] < ans)
{
ans = preans[i] + lasans[i];
x = i;
}
}
printf("%lld %lld\n", a[x].x, ans);
return 0;
}