CF1223C Save the Nature
题意:
有n张票需要卖出,你可以选择任意数字,做任意序列。
- 第i张能被a整除会拿出x%来捐赠。
- 第i张能被b整除会拿出y%来捐赠。
- 如果这张票的位置能同时被a和b整除则拿出(x+y)%来捐赠。
- 给出票价均是100的倍数,不需要任何舍入。
现在需要找到用最小的门票数量n来至少赚取k数量的钱
思路:
因为票的位置可以随意排列,可以选择利用贪心策略来找到用更少的门票数量来赚取更多的钱,但我们不知道如何找到如何使用最小的门票数量来至少赚取k数量的钱,所以需要对每次贪心后得到的钱进行遍历找到最小门票数量,为了降低时间复杂度,因为门票价格是有序的,所以可以使用二分查找。最终时间复杂度是排序+二分的时间复杂度O(nlog2n)
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <functional>
#include <set>
#define int long long
#define MAXN 200010
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
using namespace std;
int arr[MAXN];
int arr2[MAXN];
signed main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n;
int t;
cin >> t;
while (t--) {
int x, y, a, b, k;
int ans = -1;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> arr[i];
arr[i] /= 100;//因为题目给出票价是100的倍数,所以这里直接处理
}
cin >> x >> a;
cin >> y >> b;
cin >> k;
auto search = [=](int n) {//查找票价最高是多少
int sum = 0;
for (int i = 1; i <= n; ++i) {
arr2[i] = 0;
if (i % a == 0) {
arr2[i] += x;
}
if (i % b == 0) {
arr2[i] += y;
}
}
sort(arr2 + 1, arr2 + 1 + n, greater<int>());//从大到小排序
for (int i = 1; i <= n; ++i) {
sum += arr[i] * arr2[i];
}
return sum >= k;
};
sort(arr + 1, arr + 1 + n, greater<int>());
int l=1, r=n;
while (l<=r) {
int mid = (l + r) / 2;
if (search(mid)==true) {
ans = mid;
r = mid - 1;
}
else {
l = mid + 1;
}
}
cout << ans << endl;
}
return 0;
}