题目传送门
超级水题 , 谁都可以拿的经验
考察贪心 + 堆(最简单的用优先队列实现)
题面
给定 $ n$ 个数组和每个数组的常数 \(x\) 和长度 \(l\) ,
给定每个数组的 $a_i $ 、 \(b_i\) ,
定义是可以实施 \(k\) 次把某个 \(b_i\) 换成 \(a_i\) ,
当前数组的贡献是乘积 , 总贡献是所有数组贡献的和 。
保证 \(b_i\le a_i\) 。
求出最小总贡献
思路
其实不管是 \(b_i\le a_i \ \ or \ \ b_i \ge a_i\) , 这个题目的做法都是一样的
我们在输入的同时预处理完当前数组的乘积 , 同时也可以得出当前数组每个单元的 \((a_i-b_i)/a_i\) 也就是这个单元如果变化了 , 对当前数组的变化率 。
$\ $
sort
他 (言简意赅。
$\ $
我们考虑计算出他们对于原答案的变化量 (这一步详见代码,有个细节需要调,这一步的正确性在 sort
这一步中体现), 然后我们取其中 \(\min(l,k)\) 个元素丢进优先队列 。
最后输入完了也处理完了 , 只要取 \(k\) 个变化量减一减不加修饰的原答案 , 就出来了最小值了 。
\(\Large \mathcal CODE\)
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
using namespace std;const int N = 5e5 + 10;
int a[N], b[N];
priority_queue<int> q;
int n, k;
pair<long double, int> ans[N];
int res;main(void)
{ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int tmp;cin >> n >> k;while (n--) {int x, l;cin >> x >> l;int now = x;for (int i = 1; i <= l; i++) {cin >> a[i];now *= a[i];}res += now;for (int i = 1; i <= l; i++) {cin >> b[i];}for (int i = 1; i <= l; i++) {ans[i].fi = 1.l * (a[i] - b[i]) / a[i];ans[i].se = i;}sort(ans + 1, ans + 1 + l);for (int i = 1; min(k, l) >= i; i++) {tmp = now / a[ans[i].se] * b[ans[i].se];q.push(tmp);now -= tmp;}}for (int i = 1; i <= k; i++) {res -= q.top();q.pop();}cout << res << endl;
}