NewTrain1 T5: Boss单挑战
题目分析
(看到这种打怪的题,一般不是贪心就是DP...)
我们发现对于此题,状态太多以至于无法贪心,所以我们只好DP。
因为 魔法攻击 与 普通攻击和特技攻击 是相对独立的,所以可以分开来考虑。
令fm[i],fs[i]分别为 只使用魔法攻击 与 只是用普通攻击和特技攻击 到第i回合(结束)所能造成伤害的最大值(先不管本人死活)。
再令 gm[i][j],gs[i][j]分别为到了第i回合(结束),魔法量/愤怒值剩下j点所能造成的最大伤害(先不管本人死活)。
那么对于每个 fm[i]与fs[i] 扫一遍更新答案。
考虑如何维护gm[i][j],gs[i][j]。
有两种操作:
1.回复魔法值/愤怒值。
2.使用技能。
分别转移即可。
考虑如何得出最终答案,首先我们先求出不论死活的情况下,最少几回合可以杀掉Boss。
令dp[i][j] 表示到了第i回合(结束),血量为j, 使用的技能+普攻总数的最大值。
同样有两种操作:
1.回复生命值
2.使用一次技能/普攻
分别转移即可。
若某个dp[i][j]达到了上面所说的最少回合数,那么说明此时采取最优策略的话已经可以把Boss杀死了,那么可以直接输出该答案。
那么如何判断平局呢?
如果第i+1轮有数据,就说明可以活到i+1轮,就输出Tie。
反之则必输。
1 #include<bits/stdc++.h> 2 #define INTMAX 2147483647LL 3 #define PII pair<int,int> 4 #define MK make_pair 5 #define re register 6 #define clr(x) memset(x,0,sizeof(x)) 7 using namespace std; 8 typedef long long ll; 9 const double Pi=acos(-1.0); 10 const int Inf=0x3f3f3f3f; 11 const int MAXN=1e3+10; 12 inline int read(){ 13 re int x=0,f=1,ch=getchar(); 14 while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar(); 15 while(isdigit(ch))x=x*10+ch-48,ch=getchar(); 16 return x*f; 17 } 18 inline ll readll(){ 19 re ll x=0,f=1,ch=getchar(); 20 while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar(); 21 while(isdigit(ch))x=x*10+ch-48,ch=getchar(); 22 return x*f; 23 } 24 25 int T,n,m,hp,mp,sp,dhp,dmp,dsp,mp_cnt,sp_cnt,x; 26 int a[MAXN],ump[MAXN],vmp[MAXN],usp[MAXN],vsp[MAXN]; 27 int fm[MAXN],gm[MAXN][MAXN],fs[MAXN],gs[MAXN][MAXN],dp[MAXN][MAXN]; 28 inline void Up(int &x,int y){if(x<y) x=y;} 29 inline void Solve(){ 30 clr(fm);clr(gm);clr(fs);clr(gs); 31 n=read();m=read();hp=read();mp=read();sp=read();dhp=read();dmp=read();dsp=read();x=read(); 32 for(int i=1;i<=n;++i) a[i]=read(); 33 mp_cnt=read();for(int i=1;i<=mp_cnt;++i) ump[i]=read(),vmp[i]=read(); 34 sp_cnt=read();for(int i=1;i<=sp_cnt;++i) usp[i]=read(),vsp[i]=read(); 35 for (int i=0;i<=n;++i){ 36 for(int j=0;j<=mp;++j) Up(fm[i],gm[i][j]); 37 if(i<n) 38 for(int j=0;j<=mp;++j){ 39 Up(gm[i+1][min(mp,j+dmp)],gm[i][j]); 40 for(int k=1;k<=mp_cnt;++k) 41 if(j>=ump[k]) 42 Up(gm[i+1][j-ump[k]],gm[i][j]+vmp[k]); 43 } 44 } 45 for(int i=0;i<=n;++i){ 46 for(int j=0;j<=sp;++j) Up(fs[i],gs[i][j]); 47 if(i<n) 48 for(int j=0;j<=sp;++j){ 49 Up(gs[i+1][min(sp,j+dsp)],gs[i][j]+x); 50 for(int k=1;k<=sp_cnt;++k) 51 if(j>=usp[k]) 52 Up(gs[i+1][j-usp[k]],gs[i][j]+vsp[k]); 53 } 54 } 55 int mn=Inf; 56 for(int i=0;i<=n;++i) 57 for(int j=0;j<=n;++j) 58 if(fm[i]+fs[j]>=m) 59 mn=min(mn,i+j); 60 memset(dp,192,sizeof(dp)); 61 dp[1][hp]=1; 62 for(int i=1;i<=n;++i){ 63 for(int j=1;j<=hp;++j){ 64 if(dp[i][j]>=mn){ 65 printf("Yes %d\n",i); 66 return; 67 } 68 } 69 for(int j=1;j<=hp;++j){ 70 if(min(hp,j+dhp)>a[i]) Up(dp[i+1][min(hp,j+dhp)-a[i]],dp[i][j]); 71 if(j>a[i]) Up(dp[i+1][j-a[i]],dp[i][j]+1); 72 } 73 } 74 for(int i=1;i<=hp;++i) 75 if(dp[n+1][i]>=0){ 76 puts("Tie");return; 77 } 78 puts("No"); 79 } 80 int main(){ 81 T=read(); 82 while(T--) Solve(); 83 return 0; 84 }