学习C++从娃娃抓起!记录下蓝桥杯备考比赛学习过程中的题目,记录每一个瞬间。
附上汇总贴:蓝桥杯备考冲刺必刷题(C++) | 汇总-CSDN博客
3829 大石头的搬运工
【题目描述】
在一款名为”大石头的搬运工“的游戏中,玩家需要操作一排
n
n
n堆石头,进行
n
−
1
n-1
n−1轮游戏。
每一轮,玩家可以选择一堆石头,并将其移动到任意位置。
在
n
−
1
n-1
n−1轮移动结束时,要求将所有的石头移动到一起(即所有石头的位置相同)即为成功。
移动的费用为石头的重量乘以移动的距离。例如,如果一堆重量为
2
2
2的石头从位置
3
3
3移动到位置
5
5
5,那么费用为
2
×
(
5
−
3
)
=
4
2\times (5-3)=4
2×(5−3)=4。
请计算出所有合法方案中,将所有石头移动到一起的最小费用。
可能有多堆石头在同一个位置上,但是一轮只能选择移动其中一堆。
【输入】
第一行一个整数
n
n
n,表示石头的数量。
接下来
n
n
n行,每行两个整数
w
i
w_i
wi和
p
i
p_i
pi,分别表示第
i
i
i个石头的重量和初始位置。
【输出】
输出一个整数,表示最小的总移动费用。
【输入样例】
3
2 3
3 1
1 5
【输出样例】
8
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, minn=1e18;
struct node {
int w, p;
}rock[100005];
int pre[100005], nex[100005];
bool cmp(node x, node y) {
return x.p<y.p;
}
signed main()
{
cin >> n; // 输入n
for (int i=1; i<=n; i++) { // 输入n堆石头的重量和位置
cin >> rock[i].w >> rock[i].p;
}
sort(rock+1, rock+n+1, cmp); // 按照位置从小到大排序
int s = 0; // 定义重量之和,初始为0
for (int i=1; i<=n; i++) { // 遍历n堆石头,pre记录i之前的石头移动到i这个位置的费用
pre[i] = pre[i-1]; // 先将前一个位置的费用赋值给本位置
pre[i] += s * (rock[i].p-rock[i-1].p); // 再加上将前面所有的石头移动到本位置的费用
s += rock[i].w; // 更新石头的总重量
}
s = 0; // 重置重量之和
for (int i=n; i>=1; i--) { // 遍历n堆石头,nex记录i之后的所有石头移动到i这个位置的费用
nex[i] = nex[i+1]; // 先将后一个位置的费用赋值给本位置
nex[i] += s * (rock[i+1].p-rock[i].p); // 再加上将后面所有的石头移动到本位置的费用
s += rock[i].w; // 更新石头的总重量
}
for (int i=1; i<=n; i++) { // 将每个位置的前缀和、后缀和都加起来,计算最小值
minn = min(minn, pre[i]+nex[i]);
}
cout << minn << endl; // 输出最小值
return 0;
}
【运行结果】
3
2 3
3 1
1 5
8