CF1570C 题解
一道纯粹的贪心题。
思路分析
通过观察,我们可以发现,每个瓶子所需要的射击次数的增长是与 \(x\) 密切相关的。
这样我们很容易想到,如果我们将耐久度大的瓶子放在后面射击,那么 \(x\) 就会较大,因而导致最终的射击次数变大。
说到这儿,思路已经显而易见了。我们可以对 \(a\) 数组根据耐久度从大到小排序,然后模拟题意进行计算即可。
贪心证明
请记住这一点:贪心是一定需要证明的!
感性地看,贪心是没有问题的。但是,我们应该如何证明呢?
我们假定将 \(a_i\) 放在第 \(i\) 个进行射击,\(a_j\) 放在第 \(j\) 个进行射击,这样可以使得最终得到的结果最优。(\(a_i>a_j\),\(i>j\))
这样得到的结果是 \(a_i\times i+a_j\times j+2\)。
如果我们将这两个罐子进行交换,那么我们所得到的结果变为 \(a_i\times j+a_j\times i+2\)。
容易得出,后一个式子是小于前一个式子的。
这样,我们就用反证法证明了贪心的正确性。
程序实现
请注意,这份代码的最低编译环境需要是 C++11 的,C++98 将无法编译通过。
#include <bits/stdc++.h>
using namespace std;
struct jar { // 罐子结构体
int t; // 耐久度
int index; // 编号
};
int n, ans;
int main() {
cin >> n;
vector<jar> a(n);
for (int i = 0; i < n; i++) cin >> a[i].t, a[i].index = i + 1;
sort(a.begin(), a.end(), [](const jar &j1, const jar &j2){
return j1.t > j2.t;
}); // 对a数组进行从大到小的排序,比较函数会在后面介绍
for (int i = 0; i < n; i++)
ans += i * a[i].t + 1; // 依据题意模拟
cout << ans << endl;
for (auto x : a) cout << x.index << " "; // 遍历输出
return 0;
}
lambda 函数。
在 C++11 中,定义了 lambda 函数,它的使用是这样的:
[/*获取值列表*/](/*参数列表*/){}
花括号中就像平时一样写入函数内容。这只是简单的解释,如果想要更深入地了解可以自行上网查找资料。
浙公网安备 33010602011771号