NYOJ 2355: 点兵点将 (脑洞题)

题目链接

题目描述

众所不知,LLM是一个红警3的高手,由于要出题所以好几天没有玩结果连简单的电脑都打不过了,因此LLM就可耻的开了外挂虐电脑,外挂的效果是这样的:
当LLM消灭一个属性为ai的单位时,他就能免费制造一个属性为bi的单位,如果他犹豫了一下(甚至可能手速慢了一点)就会错失良机,不能再免费制造它
为了简化这个问题,我们假设如果一个A属性和一个B属性的去同时打一个C属性的单位(A+B <=C)那么A和B会死亡,而C的属性会剩下C-A-B
现在假设LLM初始有一个属性为n的单位,由于其上司的吃喝嫖赌,欠了3.5个亿带着小姨子跑了(不懂什么梗请百度《浙江温州江南皮革场倒闭了》)所以LLM没有任何金钱,现在它要按顺序消灭m个敌人,为了磨练自己的技术,LLM希望自己制造的总单位数越少越好,请问LLM制造的单位数量最少是多少?
输入

每个测试文件包含不多于10组测试样例
每个测试样例第一行为n和m
接下来两行各m个数字第二行为ai,第三行为bi
1<=m<=50000
1<=ai,bi,n<=1000
输出

输出仅包含一行,为一个整数,代表最少需要制造的单位数量
如果LLM开外挂都无法打败敌人,输出-1
样例输入

2 2
1 1
10 10
2 3
1 10 1
1 10 10
样例输出

0
-1
提示

多组测试数据

来源

河南省多校脸萌第六场

非常不错的一道题,我以为最开始觉得是dp,n于sum(a)的差就是背包容量,然后拿最少的b,但是是按顺序打怪的,可以没拿后面的b时就已经打不过了当前的a,所以一直没做出来,还是自己太菜了

正确的姿势是把每次打到的a对应可以获得的b放到一个堆里面,然后碰到一个打不过的a时,就从堆里面拿b优先拿最大的,记录拿的个数,如果把堆里面的b拿完仍然打不过,就输出-1

代码如下:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAX = 50010;
int a[MAX],b[MAX];
int n,m;
int main(void){

    while(scanf("%d %d",&n,&m) != EOF){
        for(int i=1;i<=m;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)
            scanf("%d",&b[i]);
        priority_queue<int,vector<int>,less<int> >q;
        int now = n,res = 0;//now代表当前的属性值 
        for(int i=1;i<=m;i++){
            while(now < a[i] && !q.empty()){//从堆里拿b 
                int x = q.top();q.pop();
                now += x;
                res++;
            }
            if(now < a[i]){
                res = -1;
                break;
            }
            else
                now -= a[i];
            q.push(b[i]);
        }
        printf("%d\n",res);
    }
    return 0;
}

你可能感兴趣的:(模拟题,思维题)