题解:P14174 【MX-X23-T4】卡常数
题目传送门
超级水题 , 谁都可以拿的经验
考察贪心 + 堆(最简单的用优先队列实现)
题面
给定 $ 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;
}

浙公网安备 33010602011771号