51Nod 1110 距离之和最小 V3(中位数+权值转化为个数)

来源:互联网 发布:cmd 关闭端口 编辑:程序博客网 时间:2024/06/05 19:15

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
X轴上有N个点,每个点除了包括一个位置数据X[i],还包括一个权值W[i]。点P到点P[i]的带权距离 = 实际距离 * P[i]的权值。求X轴上一点使它到这N个点的带权距离之和最小,输出这个最小的带权距离之和。
Input
第1行:点的数量N。(2 <= N <= 10000)
第2 - N + 1行:每行2个数,中间用空格分隔,分别是点的位置及权值。(-10^5 <= X[i] <= 10^5,1 <= W[i] <= 10^5)
Output
输出最小的带权距离之和。
Input示例
5
-1 1
-3 1
0 1
7 1
9 1
Output示例
20

解题思路

  把权值为w的点拆成w个权值为1的点,这样就变成了经典问题,这些点到他们位置的中位数总花费最小(如果是偶数个点,在中间两个点的闭区间内任一一点都可以)。

AC代码

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <vector>#include <queue>#include <stack>#include <cmath>#include <cstdlib>#include <string>#include <map>using namespace std;#define INF 0x3f3f3f3f#define LL long long#define fi first#define se second#define mem(a,b) memset((a),(b),sizeof(a))const int MAXN=100000+3;int N;pair<LL, LL> a[MAXN];//pos, valLL pre_num[MAXN], suf_num[MAXN];int main(){    scanf("%d", &N);    for(int i=1;i<=N;++i)        scanf("%lld%lld", &a[i].fi, &a[i].se);    sort(a+1, a+1+N);    for(int i=1;i<=N;++i)        pre_num[i]=pre_num[i-1]+a[i].se;    for(int i=N;i>0;--i)        suf_num[i]=suf_num[i+1]+a[i].se;    LL mid=-1;    for(int i=1;i<=N;++i)        if(pre_num[i-1]+a[i].se>=suf_num[i+1] && pre_num[i-1]<=a[i].se+suf_num[i+1])        {            mid=a[i].fi;            break;        }    LL ans=0;    for(int i=1;i<=N;++i)        ans+=abs(a[i].fi-mid)*a[i].se;    printf("%lld\n", ans);    return 0;}
阅读全文
0 0
原创粉丝点击