HDU 3646 DP + 二分

来源:互联网 发布:linux与windows对比 编辑:程序博客网 时间:2024/05/15 09:19

链接: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;}


原创粉丝点击