蓝桥杯3829 大石头的搬运工

蓝桥杯3829 大石头的搬运工


问题描述

在一款名为”大石头的搬运工“的游戏中,玩家需要操作一排 n 堆石头,进行n−1 轮游戏。

每一轮,玩家可以选择一堆石头,并将其移动到任意位置。

在 n−1 轮移动结束时,要求将所有的石头移动到一起(即所有石头的位置相同)即为成功。

移动的费用为石头的重量乘以移动的距离。例如,如果一堆重量为 2 的石头从位置 3 移动到位置 5,那么费用为 2×(5−3)=4。

请计算出所有合法方案中,将所有石头移动到一起的最小费用。

可能有多堆石头在同一个位置上,但是一轮只能选择移动其中一堆。

输入格式

第一行一个整数 n,表示石头的数量。

接下来 n 行,每行两个整数 wi和 pi,分别表示第 i 个石头的重量和初始位置。

输出格式

输出一个整数,表示最小的总移动费用。

样例输入
3
2 3
3 1
1 5
样例输出
8
说明

一种最优的移动方式是:

首先,将第一个石头移动到位置 1,费用为 2×(3−1)=4;

然后,将第三个石头移动到位置 1,费用为 1×(5−1)=4。

所以最小的总移动费用为 4+4=8。

数据范围

对于 20% 的测试样例,1≤n≤103
对于 100% 的测试样例,1≤n≤105,1≤wi ,pi ≤106

运行限制

语言:C++
最大运行时间:1s
最大运行内存:512M

题目信息
  • 难度: 中等
  • 标签: 前缀和, 枚举
  • 传送门

参考题解

c++版:

//核心在于一堆石头的消耗只需要考虑从起始位置挪动到终点位置
//出于对数据量的考虑,防止超时
//我们可以考虑先对石头的位置进行排序
//通过维护前缀和数组pre[i]用来记录从起始位置到第i个石头全部挪到第i个石头的位置的消耗
//维护后缀和数组nex[i]记录从末尾位置到第i个石头全部挪到第i个石头的位置的消耗
#include <bits/stdc++.h>
#define p first
#define w second
using ll=long long;//注意开ll,防止数据溢出
using namespace std;
const int N=1e5+10;//参考n的范围去定义
int n;
pair<int,int>pr[N];//利用键值对存储,注意pair的默认排序是通过pair.first
ll pre[N],nex[N];  
ll sum_w;
ll res=LONG_LONG_MAX;//注意初始化成最大值,以此通过min函数求小值
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>pr[i].w>>pr[i].p;
	}
	sort(pr+1,pr+n+1);
	for(int i=1;i<=n;i++){
		pre[i]+=pre[i-1]+sum_w*(pr[i].p-pr[i-1].p);
		sum_w+=pr[i].w;
	}
	sum_w=0;
	for(int i=n;i>=1;i--){
		nex[i]+=nex[i+1]+sum_w*(pr[i+1].p-pr[i].p);
		sum_w+=pr[i].w;
	}
	for(int i=1;i<=n;i++)
		res=min(res,pre[i]+nex[i]);
	cout<<res;
  	return 0;
}
时间复杂度分析

排序的时间复杂度为O(nlogn),计算pre,nex,pre+nex的时间复杂度为O(n)
所以这个方法的时间复杂度为O(nlogn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值