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 }

猜你喜欢

转载自www.cnblogs.com/LI-dox/p/11261527.html