非常难写的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;
}