调和级数枚举+二分查询。
现在有m只怪兽要杀死,给定n种可选择的士兵,每次选择一种,同种士兵可以选多个。当士兵的攻击力之和大于怪兽的攻击力时,就可以杀死怪兽。每种士兵的雇用价格不一样,请你决定杀死当前怪兽的最小花费(不得超过C金币)。
做法:定义f[i]为花费i元能得到的最大攻击力,若j是i的倍数,则花费j元可以得到攻击力f[i] * j / i。所以可以调和级数枚举这个dp的过程。调和级数结束之后,f[i] = max(f[i],f[i-1)),保证整个数组连续递增,便于二分查询。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5, mod = 998244353;
struct sb{
int c, d, h;
}a[N];
struct gs{
int h, d;
} b[N];
int f[N];
signed main()
{
int tt;
tt = 1;
while(tt--)
{
int n, C;
cin >> n >> C;
for (int i = 1; i <= n; i++) {
cin >> a[i].c >> a[i].d >> a[i].h;
f[a[i].c] = max(f[a[i].c], a[i].d * a[i].h);
}
for (int i = 1; i <= C; i++) {
if (!f[i]) continue;
for (int j = i; j <= C; j+=i) {
f[j] = max(f[j], f[i] * j / i);
}
}
for (int i = 1; i <= C; i++) f[i] = max(f[i], f[i - 1]);
int m;
cin >> m;
for (int i = 1; i <= m; i++) {
int h, d;
cin >> h >> d;
int kk = h * d;
int l = 1, r = C;
while(l < r)
{
int mid = (l + r) >> 1;
if (f[mid] > kk) r = mid;
else l = mid + 1;
}
if (f[l] > kk) printf("%lld ", l);
else printf("-1 ");
}
}
return 0;
}