1. 程式人生 > >51 Nod 1110距離之和最小V3

51 Nod 1110距離之和最小V3

1110 距離之和最小 V3

  1. 1 秒
  2.  
  3. 131,072 KB
  4.  
  5. 40 分
  6.  
  7. 4 級題

X軸上有N個點,每個點除了包括一個位置資料X[i],還包括一個權值W[i]。點P到點P[i]的帶權距離 = 實際距離 * P[i]的權值。求X軸上一點使它到這N個點的帶權距離之和最小,輸出這個最小的帶權距離之和。

 收起

輸入

第1行:點的數量N。(2 <= N <= 10000)
第2 - N + 1行:每行2個數,中間用空格分隔,分別是點的位置及權值。(-10^5 <= X[i] <= 10^5,1 <= W[i] <= 10^5)

輸出

輸出最小的帶權距離之和。

輸入樣例

5
-1 1
-3 1
0 1
7 1
9 1

輸出樣例

20

由於最右端點-最左端點的距離最大不會超過200000,一次從左往右掃一遍,在過程中維護兩個集合:在當前位置左邊的點,和在當前位置右邊的點。走的時候更新ans即可。詳情如下:


#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
#include<cmath>
#include<math.h>
#include<queue>
#include<set>
#include<map>
#include<iomanip>
#include<algorithm>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
int N;
int x[10005];
int w[10005];
int id[10005];
bool cmp(int i,int j)
{
    return x[i]<x[j];
}
ll L,R;
ll ans=0x3f3f3f3f3f3f3f3f;
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
    scanf("%lld",&N);
    for(int i=0;i<N;i++){scanf("%d%d",&x[i],&w[i]);R+=w[i];}
    for(int i=0;i<N;i++)id[i]=i;
    sort(id,id+N,cmp);
    int pos=x[id[0]];
    int now=1;
    ll pre=0;
    for(int i=1;i<N;i++)
    {
        pre+=1ll*(x[id[i]]-pos)*w[id[i]];
    }
    ll current=0;
    L=w[id[0]];R-=w[id[0]];
    for(;pos<=x[id[N-1]];)
    {
        current=pre+L-R;
        pos++;
        ans=min(ans,current);
        pre=current;
        if(pos==x[id[now]])
        {
            L+=w[id[now]];
            R-=w[id[now]];
            now++;
        }
    }
    printf("%lld\n",ans);
    return 0;
}