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 函数,它的使用是这样的:

[/*获取值列表*/](/*参数列表*/){}

花括号中就像平时一样写入函数内容。这只是简单的解释,如果想要更深入地了解可以自行上网查找资料。

posted @ 2023-09-10 14:11  群星之路  阅读(21)  评论(0)    收藏  举报