2017百度之星资格赛 1003:度度熊与邪恶大魔王(DP)

度度熊与邪恶大魔王

Time limit:1000 ms Memory limit:65536 kB


Problem Description

度度熊为了拯救可爱的公主,于是与邪恶大魔王战斗起来。

邪恶大魔王的麾下有n个怪兽,每个怪兽有a[i]的生命值,以及b[i]的防御力。

度度熊一共拥有m种攻击方式,第i种攻击方式,需要消耗k[i]的晶石,造成p[i]点伤害。

当然,如果度度熊使用第i个技能打在第j个怪兽上面的话,会使得第j个怪兽的生命值减少p[i]-b[j],当然如果伤害小于防御,那么攻击就不会奏效。

如果怪兽的生命值降为0或以下,那么怪兽就会被消灭。

当然每个技能都可以使用无限次。

请问度度熊最少携带多少晶石,就可以消灭所有的怪兽。

Input

本题包含若干组测试数据。

第一行两个整数n,m,表示有n个怪兽,m种技能。

接下来n行,每行两个整数,a[i],b[i],分别表示怪兽的生命值和防御力。

再接下来m行,每行两个整数k[i]和p[i],分别表示技能的消耗晶石数目和技能的伤害值。

数据范围:

1<=n<=100000

1<=m<=1000

1<=a[i]<=1000

0<=b[i]<=10

0<=k[i]<=100000

0<=p[i]<=1000

Output

对于每组测试数据,输出最小的晶石消耗数量,如果不能击败所有的怪兽,输出-1

Sample Input

1 2
3 5
7 10
6 8
1 2
3 5
10 7
8 6

Sample Output

6
18

解题思路:

注意到防御值最大才为10,所以肯定是用防御力来遍历。设dp[j][i]为防御力为 i ,打出 j点伤害以上时所需的最少晶石。
对于第u个技能来说,如果p[u]<= i,说明根本打不出伤害,不用管。
反之,伤害则为 dmg=p[u]-i, 这时候 又有两种情况:
如果dmg>=j,说明靠这一个技能就够打出足够伤害了,那么肯定是用消耗晶石最少的那个技能,dp[j][i]=min{k[u]}
反之,光靠这个技能不足以打出足够的伤害,那么就需要借助前面的dp值来计算,dp[j-dmg][i]代表同在i防御力,打出j-dmg的伤害的最少晶石,因为dp[j-dmg][i]数量的晶石已经可以打出 j-dmg 的伤害了,此时再加上这第u个技能的伤害,就可以打到 j 以上,晶石数则为dp[j-dmg][i]+k[u],与上面一样,因为不知道哪个技能消耗的晶石最少,所以这里也取一个最小值。


Code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
const int maxn=100000+5;
const int maxm=1000+5;

LL a[maxn],b[maxn];
LL k[maxm],p[maxm];
LL dp[maxm][15];//防御力为j,打出i点伤害以上时所需的最少晶石

LL max(LL a,LL b)
{
    return a>b?a:b;
}
LL min(LL a,LL b)
{
    return a<b?a:b;
}


int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        LL up1=0,up2=0,hp=0;
        for(int i=0; i<n; i++)
        {
            scanf("%I64d%I64d",&a[i],&b[i]);
            up1=max(up1,b[i]);
            hp=max(hp,a[i]);
        }

        for(int i=0; i<m; i++)
        {
            scanf("%I64d%I64d",&k[i],&p[i]);
            up2=max(up2,p[i]);
        }
        if(up1>=up2)
        {
            printf("-1\n");
            continue;
        }
        mem(dp,0);
        for(int i=0; i<=10; i++)//防御
        {
            for(int j=1;j<=hp;j++)//造成伤害值
            {
                dp[j][i]=1e18;
                for(int u=0;u<m;u++)//第u个技能
                {
                    LL dmg=p[u]-i;//第u个技能能造成的伤害
                    if(dmg<=0)
                        continue;
                    if(dmg>=j)
                    {
                        dp[j][i]=min(dp[j][i],k[u]);
                    }
                    else
                    {
                        dp[j][i]=min(dp[j][i],dp[j-dmg][i]+k[u]);
                    }
                }
            }
        }
        LL ans=0;
        for(int i=0;i<n;i++)
        {
            ans+=dp[a[i]][b[i]];
        }
        printf("%I64d\n",ans);

    }
    return 0;
}
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值