Loading

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;
}
posted @ 2022-04-25 18:18  dgsvygd  阅读(70)  评论(0编辑  收藏  举报