1. 程式人生 > >51Nod 1110 距離之和最小 V3(中位數+權值轉化為個數)

51Nod 1110 距離之和最小 V3(中位數+權值轉化為個數)

基準時間限制: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, val LL 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; }