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
",ans);
    return 0;
}



原文地址:https://www.cnblogs.com/linruier/p/9886225.html