【XDOJ】小W的塔防
原题:
小W在成功拿到iPhone后,下载了一个塔防游戏。游戏的目标是阻止僵尸穿过地图。
地图可以看作一条长度为n的线段,这条线段被划分为n条单位长度的小线段。僵尸需要花费t秒才能通过一条小线段。在每条小线段中,小W可以放置1个塔。塔有3种:
红色塔,每秒对正在通过塔的敌人造成x点伤害。
绿色塔,每秒对已经通过塔的敌人造成y点伤害。
蓝色塔,使已经通过塔的敌人减速,需要多花费z秒才能通过1单位长度。
“正在通过”定义为僵尸处于塔所在的单位长度小线段,“已经通过”定义为僵尸已经离开了这条小线段。
绿色塔、蓝色塔的效果可以叠加。换句话说,如果一个僵尸已经通过了a个绿色塔,b个蓝色塔,它将每秒受到来自绿色塔的ay点伤害,并且花费t+bz秒才能通过1单位长度。
小W希望知道,他至多可以给僵尸造成多少伤害。
1<=n<=100,0<=x,y,z<=60000,1<=t<=3
n很小,冰塔和毒塔的数量又不可能超过n
所以一眼f[i][j][k] n^3 DP,表示僵尸走到第i个线段,踩了j个毒塔,k个冰塔能吃掉的最大伤害
但是我没有1A,问题在哪里呢
一开始我是这样写的
1 for(int i=1;i<=n;++i) 2 for(int j=0;j<=i;++j) 3 for(int k=0;j+k<=i;++k){ 4 f[i][j][k]=max(f[i][j][k],f[i-1][j][k]+(x+j*y)*(t+k*z)); 5 if(j) f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k]+(j-1)*y*(t+k*z)); 6 if(k) f[i][j][k]=max(f[i][j][k],f[i-1][j][k-1]+j*y*(t+(k-1)*z)); 7 }
然后f初值是0
结果样例没过,因为这样子有可能从f[0][1][0]转移到f[1][1][0]
然后我草率地把j<=i和j+k<=i改成j<i和j+k<i
显然这样是不对滴,注意j和k表示的是走过第i个线段时,踩了j个毒塔k个冰塔,之前的表述是不清楚的
喜闻乐见地WA了
正确改法应该是f初值全设-INF,f[0][0][0]设成0
突然想起来这个做法还是挺常见的,用来防止非法状态乱入
可能是退坑一年忘了吧哈哈
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 long long n,x,y,z,t; 8 long long f[110][110][110]; 9 void rvs(){ 10 for(int i=0;i<=n;++i) 11 for(int j=0;j<=n;++j) 12 for(int k=0;k<=n;++k) 13 f[i][j][k]=-9999999999999999LL; 14 f[0][0][0]=0; 15 return ; 16 } 17 int main(){ 18 //freopen("ddd.in","r",stdin); 19 while(scanf("%lld%lld%lld%lld%lld",&n,&x,&y,&z,&t)!=EOF){ 20 rvs(); 21 for(int i=1;i<=n;++i) 22 for(int j=0;j<=i;++j) 23 for(int k=0;j+k<=i;++k){ 24 f[i][j][k]=max(f[i][j][k],f[i-1][j][k]+(x+j*y)*(t+k*z)); 25 if(j) f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k]+(j-1)*y*(t+k*z)); 26 if(k) f[i][j][k]=max(f[i][j][k],f[i-1][j][k-1]+j*y*(t+(k-1)*z)); 27 } 28 long long ans=0; 29 for(int i=0;i<=n;++i) 30 for(int j=0;j<=n;++j) 31 ans=max(ans,f[n][i][j]); 32 printf("%lld\n",ans); 33 } 34 return 0; 35 }