又一次跌倒在字母大小写上。。。QAQ。。
可以发现回血,魔攻,特攻都是相互独立的,因此可以分开来分别dp,然后可以得到在不死的情况下第i回合能进行多少次攻击,以及i回合最多能魔攻多少血,特攻多少血,然后合起来就得到答案了。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define clr(ar) memset(ar,0,sizeof(ar))
#define N 1005
using namespace std;
int n,m,hp,mp,sp,dhp,dmp,dsp,x,mp_cnt,sp_cnt,ump[N],vmp[N],usp[N],vsp[N];
int a[N],fm[N],gm[N][N],fs[N],gs[N][N],dp[N][N];
void up(int &x,int y){ if (x<y) x=y; }
void solve(){
clr(fm); clr(gm); clr(fs); clr(gs);
scanf("%d%d%d%d%d%d%d%d%d",&n,&m,&hp,&mp,&sp,&dhp,&dmp,&dsp,&x);
int i,j,k;
for (i=1; i<=n; i++) scanf("%d",&a[i]);
scanf("%d",&mp_cnt);
for (i=1; i<=mp_cnt; i++) scanf("%d%d",&ump[i],&vmp[i]);
scanf("%d",&sp_cnt);
for (i=1; i<=sp_cnt; i++) scanf("%d%d",&usp[i],&vsp[i]);
for (i=0; i<=n; i++){
for (j=0; j<=mp; j++) up(fm[i],gm[i][j]);
if (i<n)
for (j=0; j<=mp; j++){
up(gm[i+1][min(mp,j+dmp)],gm[i][j]);
for (k=1; k<=mp_cnt; k++)
if (j>=ump[k]) up(gm[i+1][j-ump[k]],gm[i][j]+vmp[k]);
}
}
for (i=0; i<=n; i++){
for (j=0; j<=sp; j++) up(fs[i],gs[i][j]);
if (i<n)
for (j=0; j<=sp; j++){
up(gs[i+1][min(sp,j+dsp)],gs[i][j]+x);
for (k=1; k<=sp_cnt; k++)
if (j>=usp[k]) up(gs[i+1][j-usp[k]],gs[i][j]+vsp[k]);
}
}
int mn=1000000000;
for (i=0; i<=n; i++)
for (j=0; j<=n; j++) if (fm[i]+fs[j]>=m) mn=min(mn,i+j);
memset(dp,192,sizeof(dp));
dp[1][hp]=1;
for (i=1; i<=n; i++){
for (j=1; j<=hp; j++)
if (dp[i][j]>=mn){
printf("Yes %d\n",i); return;
}
for (j=1; j<=hp; j++){
if (min(hp,j+dhp)>a[i]) up(dp[i+1][min(hp,j+dhp)-a[i]],dp[i][j]);
if (j>a[i]) up(dp[i+1][j-a[i]],dp[i][j]+1);
}
}
for (i=1; i<=hp; i++)
if (dp[n+1][i]>=0){ puts("Tie"); return; }
puts("No");
}
int main(){
int cas; scanf("%d",&cas);
while (cas--) solve();
return 0;
}
by lych
2016.4.13