Educational Codeforces Round 125 (Rated for Div. 2) D. For Gamers. By Gamers.
Educational Codeforces Round 125 (Rated for Div. 2) D. For Gamers. By Gamers.

Educational Codeforces Round 125 (Rated for Div. 2) D. For Gamers. By Gamers.

本来是上大分的(之前状态有点萎靡,小号掉了一伯分),但是这道题思路慢了导致没时间看E,排名也不是很靠前。:(

题面传送门

题意:你有n种兵和C块钱,要讨伐m个怪,这些怪是相互独立的,每种兵都有招募价格c_i,攻击力d_i和血量h_i,怪物也有各自的攻击力D_i和血量H_i,每次讨伐一个怪物只能招募一种类型的兵种(可以招募任意数量)。
怪物和佣兵是同时攻击的,也就是怪物和佣兵的攻击力实际上是秒伤。
问对于每次讨伐是否能够在C元(每次都有)的限制内完成讨伐且不存在任何一个佣兵死亡。如果可以,最少要花费多少钱;如果不行输出-1

对于第j只怪物,选择第i种兵,则需要满足:

\frac{h_i}{D_j}>\frac{H_j}{k*d_i}

将其左右通分得:

k* h_i * d_i > H_j * D_j

可以发现,我们应当构造一个新的概念叫战力值,即 攻击力 X 血量 。
但是我们仍然需要考虑k这个变量带来的影响。(比赛的时候就是一直卡在这)

经过思考,发现可以将k * h_i * d_i看作一个新的佣兵,这样我们只要考虑取一个兵即可,那么我们可以用f[i]表示花费i块钱可以取得的最大战力值来进行dp。

复杂度分析由调和级数可以知道这个是O(nlogn)的。

1~C取前缀max,对于每个查询用二分解决。(也可以对每个点当作一种兵取出以战力值为关键字排序,对花费取min,但是也是一样的效果,所以还是前一种更优)。

code:

#include <bits/stdc++.h>
#define MAXN 300005
#define MAXC 1000005
#define int long long
using namespace std;
int n,m,C,c[MAXN],b[MAXN],f[MAXC],an[MAXN];
struct coin{int x,y;}p[MAXC];
int Cmp(coin x,coin y){
    return x.y>y.y;
}
signed main(){
    cin>>n>>C;
    for(int i=1,x,y;i<=n;++i){
        cin>>c[i]>>x>>y,b[i]=x*y;f[c[i]]=max(f[c[i]],x*y);
    }
    for(int i=1;i<=C;++i)
            for(int j=1;j*i<=C;++j)f[j*i]=max(f[j*i],f[i]*j);
    for(int i=1;i<=C;++i)p[i]=(coin){i,f[i]};
    sort(p+1,p+C+1,Cmp);

    cin>>m;
    for(int i=2;i<=C;++i)p[i].x=min(p[i].x,p[i-1].x);
    for(int i=1,x,y;i<=m;++i){
        cin>>x>>y,x=x*y;
        int L=1,R=C,ans=-1;
        while(L<=R){
            int Mid=L+R>>1;
            if(p[Mid].y>x)L=Mid+1,ans=Mid;
            else R=Mid-1;
        }
        if(ans>0)an[i]=p[ans].x;
        else an[i]=-1;
    }
    for(int i=1;i<=m;++i)printf("%lld ",an[i]);
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注