2022/10/7 T3 boss挑战
题目大意:给你敌人的生命值,你的生命值、愤怒值、蓝值,愤怒值可以在普攻造成伤害的同时回复,生命和蓝值可以喝药回,愤怒值和蓝值可以放大招造成伤害,每回合你先选一种行动,行动完敌人对你造成伤害,判断规定回合内是否能赢、最早什么时候赢、会不会死。
我们考虑定义dp数组 \(f[回合数][生命值][蓝值][愤怒值]=造成伤害\) 然而根据此题的数据范围显然会又T又MLE,
考虑生命值、蓝值、愤怒值的计算互不影响,我们可以对他们分别拆开来做拆分dp,计算最终答案只需扫描结束所用的回合数1~n,用当前回合数减去活到当前回合最少喝药次数后的剩余回合数遍历对蓝系统和愤怒系统的分配回合数量的不同方案,若有可以杀死对手的方案,直接输答案为当前回合数,否则若最后一回合结束后发现没有活着的方案输“No”,其余就为“Tie”
时间复杂度\(\Theta(n^2+n(hp+mp*n1+sp*n2))\)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll t,n,m,a[10000],n1,b[100],y[100],n2,c[100],z[100],mxs[2000],mxm[2000],mnh[2000];
ll dhp,dsp,dmp,x,hp,mp,sp,fhp[2000][2000],fsp[2000][2000],fmp[2000][2000],ans,cnt,willdead;
int main(){
freopen("boss.in","r",stdin);
freopen("boss.out","w",stdout);
cin>>t;
for(int o=0;o<t;o++){
cin>>n>>m>>hp>>mp>>sp>>dhp>>dmp>>dsp>>x;
for(int i=1;i<=n;i++){
cin>>a[i];
}
cin>>n1;
for(int i=1;i<=n1;i++){
cin>>b[i]>>y[i];
}
cin>>n2;
for(int i=1;i<=n2;i++){
cin>>c[i]>>z[i];
}
for(int i=0;i<=n+1;i++){
for(int j=0;j<=1000;j++){
fhp[i][j]=1e5;
fsp[i][j]=0;
fmp[i][j]=0;
mxs[i]=0;
mxm[i]=0;
mnh[i]=1e5;
}
}
fhp[1][hp]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=hp;j++){
if(fhp[i][j]!=1e5){
if(j-a[i]>0)fhp[i+1][j-a[i]]=min(fhp[i][j],fhp[i+1][j-a[i]]);
if(j-a[i]>0&&i!=n)fhp[i+1][min(hp,j-a[i]+dhp)]=min(fhp[i][j]+1,fhp[i+1][min(hp,j-a[i]+dhp)]);//这个地方一定要判j-a[i]是否大于0,因为如果小于0就已经死了,后面补回来也无济于事(我甚至为此调了一下午)
}
mnh[i]=min(mnh[i],fhp[i][j]);
}
}
for(int j=1;j<=hp;j++){
mnh[n+1]=min(mnh[n+1],fhp[n+1][j]);
}
for(int i=0;i<=n;i++){
for(int j=0;j<=mp;j++){
fmp[i+1][min(j+dmp,mp)]=max(fmp[i+1][min(j+dmp,mp)],fmp[i][j]);
mxm[i]=max(mxm[i],fmp[i][j]);
for(int k=1;k<=n1;k++){
if(j-b[k]>=0)fmp[i+1][j-b[k]]=max(fmp[i][j]+y[k],fmp[i+1][j-b[k]]);
}
}
}
for(int i=0;i<=n;i++){
for(int j=0;j<=sp;j++){
fsp[i+1][min(sp,j+dsp)]=max(fsp[i+1][min(sp,j+dsp)],fsp[i][j]+x);
mxs[i]=max(mxs[i],fsp[i][j]);
for(int k=1;k<=n2;k++){
if(j-c[k]>=0)fsp[i+1][j-c[k]]=max(fsp[i+1][j-c[k]],fsp[i][j]+z[k]);
}
}
}
ans=0;
willdead=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=i-mnh[i];j++){
ans=max(ans,mxs[j]+mxm[i-mnh[i]-j]);
if(ans>=m){
cout<<"Yes "<<i<<endl;
break;
}
}
if(ans>=m)break;
}
if(ans<m){
if(mnh[n+1]>n)cout<<"No"<<endl;
else cout<<"Tie"<<endl;
}
}
return 0;
}