CodeForces - 734C Anton and Making Potions【二分,贪心,思维】

题意:

Anton要制作 n 瓶药水,正常制作一瓶药水的时间是 x ,且Anton有 s 点魔力值,Anton发现有两种魔法:

1号魔法有m种,每种1号魔法有两个参数 ai 和 bi,表示第 i 种1号魔法花费 bi 点魔力, 可以将他制作一瓶药水的时间从 x 变成 ai 。  2号魔法有n种,每种2号魔法有两个参数 ci 和 di ,表示第 i 种2号魔法花费 di 点魔力,可以瞬间制作 ci 瓶药水(不花费时间)。条件是1号和2号魔法都最多使用一次。

问最后制作出 n 瓶药水最短需要多长。

思路:

因为每种魔法都最多只能使用一次,所以大部分时候我们要从2号魔法中选一个先制作出 ci 瓶药水,在从1号魔法中选一个将药水制作周期变短,制作剩下的药水,所以要协调两种魔法的选择,得出最优的选择。 我们可以先将1号魔法进行排序,排序的规则是以花费从小到大排,而且花费大的魔法一定比花费小的魔法效果好,也就是时间可以减到更短。如果一种魔法比前面的更贵,但是效果一样或者更差,我们是一定不会去选他的对吧,就把他删掉。经过这样的排序后,我们就可以遍历 2 号魔法,先用2号魔法制作出药水,再用剩下的魔力买 1 号魔法,因为我们已经将1号魔法排序为越贵越好,所以我们就可以二分查找剩下的魔力值可以使用的最贵的魔法,这样求出来就会是最优的搭配,取一个最小的就可以。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long Lint;
const int max_n=2e5+100;
const Lint MaxInt=1e18+9;

struct P1{
    Lint time;
    Lint cost;
}p1[max_n];
struct P2{
    Lint num;
    Lint cost;
}p2[max_n];
int p2num=0,p1num=0;
Lint ptime,money,psum;

vector<P1> vp1;
Lint p1cost[max_n];
bool cmp(P1 n1,P1 n2){
    if(n1.cost==n2.cost) return n1.time<n2.time;
    return n1.cost<n2.cost;
}
bool cmp2(P2 n1,P2 n2){
    return n1.cost<n2.cost;
}

void fun1(){   //将第一种药水按费用排序,且越贵效果越好
    sort(p1,p1+p1num,cmp);
    Lint mintime=MaxInt;
    for(int i=0;i<p1num;i++){
        if(mintime>p1[i].time){  //花费高,且效果更好
            mintime=p1[i].time;
            vp1.push_back(p1[i]);
        }
    }
    p1num=vp1.size(); //将花费高,效果还不好的删去
    for(int i=0;i<p1num;i++)
        p1cost[i]=vp1[i].cost;
}

Lint GetTime(P2 pp2){
    Lint temp=psum-pp2.num;
    Lint mm=money-pp2.cost;
    if(mm<0) return ptime*psum;
    if(temp<=0) return 0;
    int index=upper_bound(p1cost,p1cost+p1num,mm)-p1cost;
    if(index==0) return temp*ptime;
    index--;
    return vp1[index].time*temp;
}

void solve(){
    scanf("%d%d%d",&psum,&p1num,&p2num);
    scanf("%lld%lld",&ptime,&money);
    for(int i=0;i<p1num;i++)
        scanf("%d",&p1[i].time);
    for(int i=0;i<p1num;i++)
        scanf("%d",&p1[i].cost);
    for(int i=0;i<p2num;i++)
        scanf("%d",&p2[i].num);
    for(int i=0;i<p2num;i++)
        scanf("%d",&p2[i].cost);
    fun1();
    Lint res=GetTime((P2){0,0});
    for(int i=0;i<p2num;i++){
        res=min(res,GetTime(p2[i]));
    }
    cout<<res<<endl;
}

int main(){
    solve();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值