HDU 3646 DP + 二分

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3646

题意:你有N把武器,每把武器可以对敌人造成一定的伤害(et:攻击力500,敌人血量为200,杀死敌人,攻击力剩余300),一共有K个敌人,你有M次魔法double武器的攻击力(加倍),使用武器是有规则的:武器有两个状态,一个状态为young,一个为old,新的武器状态为young,当你用它杀死一个敌人之后,状态变为old,当状态为young的时候,即使该武器剩余的攻击力不足以杀死当前的敌人,但是可以伤害他一定血量,但是为old的时候,武器攻击力不足以杀死对方,就无法攻击他(比如攻击力为200,敌人血量500,young:敌人减少200,old:敌人血量不减)。使用武器的顺序和杀人的顺序是给定的。问你最多能杀死几个人?

见解:如果没有old,young的话,这是一个水DP,有了这个状态的话,我们不好处理,主要是不知道当前武器的状态是什么,如果加一维表示当前状态的话,那么还得再来一维表示正在挑战第几个敌人,我们可以这样理解状态,dp【i】【j】表示使用完了i把武器,用了j次魔法,一共造成的伤害是多少,转移的时候,二分下现在的伤害就能知道现在在杀第a个人,然后二分再使用一把武器的造成的伤害,能知道挑战到第b个人,如果两个人不是同一个人,那说明我们无法伤害b,那么使用这把武器后我们能造成的伤害就是sum【b】了,最后二分伤害,就可以知道最多杀死几个人了,详细看代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int maxn = 105;
const int maxm = 100005;
int dp[2][maxn],life[maxm],power[maxn * maxn],N,M,K;
int sum[maxm];
int main()
{
    int cnt = 0;
    while(scanf("%d%d%d",&N,&M,&K) && N + M + K)
    {
        for(int i = 1;i <= N;i ++) scanf("%d",&power[i]);
        for(int i = 1;i <= K;i ++)
        {
            scanf("%d",&life[i]);
            sum[i] = sum[i - 1] + life[i];
        }
        int ans = 0;
        M = min(M,N);
        memset(dp,0,sizeof(dp));
        for(int i = 1;i <= N && !ans;i ++)
        {
            for(int j = 0;j <= M;j ++)
            {
                int a , b, next_a,next_b;
                a = upper_bound(sum + 1,sum + 1 + K,dp[(i - 1) & 1][j]) - sum;// now killed
                if(j)
                {
                    b = upper_bound(sum + 1,sum + 1 + K,dp[(i - 1) & 1][j - 1]) - sum;//now killed j - 1
                    next_b = upper_bound(sum + 1,sum + 1 + K,dp[(i - 1) & 1][j - 1] + (power[i] << 1)) - sum;// use power
                }
                next_a = upper_bound(sum + 1,sum + 1 + K,dp[(i - 1) & 1][j] + power[i]) - sum;//not use power
                int hurt_a = dp[(i - 1) & 1][j] + power[i],hurt_b ;
                if(a != next_a) hurt_a = sum[next_a - 1];
                if(j) hurt_b = dp[(i - 1) & 1][j - 1] + (power[i] << 1);
                if(j) if(b != next_b) hurt_b = sum[next_b - 1];
                if(j)dp[i & 1][j] = Max(hurt_a,hurt_b);
                else dp[i & 1][j] = hurt_a;
                if(dp[i & 1][j] >= sum[K])
                {
                    ans = K;
                    break;
                }
            }
        }
        if(!ans) ans =  upper_bound(sum + 1,sum + 1 + K,dp[N & 1][M]) - sum - 1;
        printf("%d\n",ans);
    }
    return 0;
}


转载于:https://www.cnblogs.com/yobobobo/archive/2012/10/26/3826806.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值