BZOJ2964: Boss单挑战 题解

非常难写的dp背包
如果我们把魔法值,怒气值,血量放在一起考虑,状态数会爆炸
但我们发现,与魔法值,怒气值,血量相关的操作是互不影响的,所以我们可以分开来dp
有一个细节要注意:每轮是主角先操作,所以如果主角干掉了Boss,事实上主角比Boss多操作了一次
与怒气值相关的操作有普攻和怒攻
与魔法值相关的操作由嗑魔法药和魔攻
与血量相关的操作有嗑血量药和被Boss打
令dp1[i][j]表示当前进行了i次怒气值相关操作,当前怒气值是j的情况下能对Boss产生的最大伤害
令dp2[i][j]表示当前进行了i次魔法值相关操作,当前魔法值是j的情况下能对Boss产生的最大伤害
令dp3[i][j]表示想要苟到第i轮的攻击时间,剩余血量是j的情况下最多能留多少次机会給进攻操作(有时不得不嗑药)
转移非常简单
对于每个dp的每一层,记录一个最大值
dp跑完了以后,枚举进行了几次怒气值相关操作和几次魔法值相关操作,然后把对应的最大值加一加,这样可以求出想要打败Boss最少要几次进攻类操作
最后枚举一下第几轮干掉Boss,算一算就好了

*感觉这题的数据有点奇怪,刚开始dp3的初始值置为0WA,改成192就莫名AC了,不理解…

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=998244353;
const LL LINF=2e16;
const int INF=1e9;
const int magic=348;
const double eps=1e-10;

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

int n,m,HP,MP,SP,DHP,DSP,DMP,X;
int a[1048];
int N1,N2;Pair b[148],c[148];

int dp1[1048][1048],dp2[1048][1048],dp3[1048][1048],DP1[1048],DP2[1048],DP3[1048],DP4[1048];

int main ()
{
    int i,j,k,ca;ca=getint();
    while (ca--)
    {
        n=getint();m=getint();HP=getint();MP=getint();SP=getint();DHP=getint();DMP=getint();DSP=getint();X=getint();
        for (i=1;i<=n;i++) a[i]=getint();
        N1=getint();for (i=1;i<=N1;i++) b[i].x=getint(),b[i].y=getint();
        N2=getint();for (i=1;i<=N2;i++) c[i].x=getint(),c[i].y=getint();
        memset(dp1,0,sizeof(dp1));memset(dp2,0,sizeof(dp2));memset(dp3,192,sizeof(dp3));
        memset(DP1,0,sizeof(DP1));memset(DP2,0,sizeof(DP2));memset(DP3,192,sizeof(DP3));
        dp3[1][HP]=1;
        for (i=1;i<=n+1;i++)
            for (j=1;j<=HP;j++)
            {
                DP3[i]=max(DP3[i],dp3[i][j]);
                if (i<=n)
                {
                    if (j-a[i]>0) dp3[i+1][j-a[i]]=max(dp3[i+1][j-a[i]],dp3[i][j]+1);
                    if (min(HP,j+DHP)-a[i]>0) dp3[i+1][min(HP,j+DHP)-a[i]]=max(dp3[i+1][min(HP,j+DHP)-a[i]],dp3[i][j]);
                }
            }
        dp1[0][SP]=0;
        for (i=0;i<=n;i++)
            for (j=0;j<=SP;j++)
            {
                DP1[i]=max(DP1[i],dp1[i][j]);
                if (i<n)
                {
                    dp1[i+1][min(SP,j+DSP)]=max(dp1[i+1][min(SP,j+DSP)],dp1[i][j]+X);
                    for (k=1;k<=N2;k++)
                        if (j-c[k].x>=0) dp1[i+1][j-c[k].x]=max(dp1[i+1][j-c[k].x],dp1[i][j]+c[k].y);
                }
            }
        dp2[0][MP]=0;
        for (i=0;i<=n;i++)
            for (j=0;j<=MP;j++)
            {
                DP2[i]=max(DP2[i],dp2[i][j]);
                if (i<n)
                {
                    dp2[i+1][min(j+DMP,MP)]=max(dp2[i+1][min(j+DMP,MP)],dp2[i][j]);
                    for (k=1;k<=N1;k++)
                        if (j-b[k].x>=0) dp2[i+1][j-b[k].x]=max(dp2[i+1][j-b[k].x],dp2[i][j]+b[k].y);
                }
            }
        int minneed=INF;
        for (i=0;i<=n;i++)
            for (j=0;j<=n;j++)
                if (DP1[i]+DP2[j]>=m) minneed=min(minneed,i+j);
        bool f=false;
        for (i=1;i<=n;i++)
            if (DP3[i]>=minneed)
            {
                printf("Yes %d\n",i);
                f=true;break;
            }
        if (f) continue;
        if (DP3[n+1]>=0) printf("Tie\n"); else printf("No\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值