CodeForces-1657D For Gamers. By Gamers.
For Gamers. By Gamers.
给出初始金币数
给出n个兵种,每个兵种有三个属性:\(c_i, d_i, h_i\)分别代表购买一只该兵种的代价,伤害,血量
同时给出m个敌人,每个敌人有两个属性\(D_i, H_i\)分别代表该敌人伤害,血量
每一次只面对一个敌人,同时刷新金币数(金币数回复初始值),并要求,每次面对敌人时,在任何一个兵不伤亡的情况下,战胜敌人所需要花费的最少金币数,如果金币数不够,则输出-1
同时给出购买兵种的约束,仅能买一种兵
二分
首先进行简单的分析:在什么情况下能战胜敌人
以给出的条件来看:
\[\frac{h_i}{D_j} > \frac{H_j}{num * d_i}
\]
化简:
\[h_i * d_i * num > H_j * D_j
\]
因此,就得到了只需要对比乘积的大小就可以知道是否能打过
接下来我们思考代价的问题,不难想出,这个代价是单调的,同时观察题目的数据范围——1e6,可以用数组储存,因此我们考虑使用二分,提前预处理所有的代价的最大乘积,然后直接二分寻找最小的代价
\(dp[i] = x\)的意义是:花费代价i,所能得到的最大乘积是x
同时状态转移为:
\[dp[j] = max(dp[j], dp[i] * (j / i), dp[j-1]), j | i
\]
对于所有的\(dp[i]\),都应该更新其i倍数的dp最大值,同时为了维护单调(取消离散化),状态还要从\(dp[i-1]\)中转移
预处理完之后,直接二分就好了
时间复杂度\(O(clogc + mlogc)\),预处理类似埃氏筛,为nlogn级别
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 1e6 + 10;
const ll inf = 1e17 + 10;
ll dp[maxn];
int main()
{
int n, len;
scanf("%d%d", &n, &len);
for(int i=0; i<n; i++)
{
ll a, b, c;
scanf("%lld%lld%lld", &a, &b, &c);
// dp[a] = b * c;
dp[a] = max(dp[a], b * c);
}
for(ll i=1; i<=len; i++)
{
dp[i] = max(dp[i], dp[i-1]);
for(ll cur=2,j=i+i; j<=len; j+=i,cur++)
dp[j] = max(dp[j], dp[i]*cur);
}
int m;
scanf("%d", &m);
for(int i=0; i<m; i++)
{
ll a, b;
scanf("%lld%lld", &a, &b);
ll tot = a * b;
tot++;
if(tot > dp[len]) printf("-1 ");
else
{
int way = lower_bound(dp, dp + len + 1, tot) - dp;
printf("%d ", way);
}
}
printf("\n");
return 0;
}