本来是上大分的(之前状态有点萎靡,小号掉了一伯分),但是这道题思路慢了导致没时间看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]);
}