题目:链接

题意

有n个石块,每一个位置有不同重量的石块,现在要进行n-1次操作,将所有的石块移动到同一个位置,特别注意,同一位置上可能有多个石头,一次操作只能移动一个石头。

思路

一开始想到直接利用中位数定理的结论,但是发现与题意有冲突,所以可以枚举移动到每一个位置上的花费,在算每一个位置上的花费时,可以采用前缀和的形式计算,比如说某位置的花费=某位置左侧位置上的花费+从左侧位置移动到该位置上的花费,右侧同理,注意重量的累加。

		pre[i] = pre[i-1];
        pre[i] += s * (a[i].p -a[i-1].p);
        s += a[i].w;

心得

不要一味的套公式!公式背后的推导要多思考。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef struct st
{
    int w;
    int p;
}St;
const int N = 1e5 + 10;
St a[N];
ll pre[N], nex[N];

bool cmp(St x, St y)
{
    return x.p < y.p;
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;cin>>n;

    for(int i = 1; i <= n; i++) cin>>a[i].w>>a[i].p;
    
    sort(a + 1,a + 1 + n,cmp);

    ll s = 0;
    for(int i = 1; i <= n; i++)
    {
        pre[i] = pre[i-1];
        pre[i] += s * (a[i].p -a[i-1].p);
        s += a[i].w;
    }

    s = 0;
    for(int i = n; i >= 1; i--)
    {
        nex[i] = nex[i+1];
        nex[i] += s * (a[i+1].p - a[i].p);
        s += a[i].w;
    }

    ll ans = 1e18;
    for(int i = 1; i <= n; i++)
    {
        ans = min(ans, pre[i] + nex[i]);
    }

    cout<<ans;
    return 0;
}