HDU 4939-E - Stupid Tower Defense-DP

题意:
题意:给出一条长为n个单位长度的直线,每通过一个单位长度需要t秒。

有3种塔,红塔可以在当前格子每秒造成x点伤害,绿塔可以在之后的格子每秒造成y点伤害,蓝塔可以使通过单位长度的时间增加z秒。问如何安排3种塔的顺序使得造成的伤害最大,输出最大伤害值


显然 红塔放在最后面是最优的,因此可以枚举i,红塔的位置就是i+1到n

那么只是看前面怎么选蓝和绿

dp[i][j]表示前面i个塔选j个蓝

我们考虑位置J放不放蓝塔时,从1到j的总伤害 //注意特判一下j=0,访问j-1会越界

__int64 tmp1=dp[i-1][j-1]+(i-j)*y*(t+(j-1)*z);  //j is blue时,在第j造成的伤害 +前i-1的伤害
__int64 tmp2=dp[i-1][j]+(i-1-j)*y*(t+j*z); //j is green,在第j造成的伤害+前i-1的伤害
dp[i][j]=max(tmp1,tmp2);

然后前i个塔里选j个蓝的方案下,我们可以得到最终包括红塔的总伤害 为:

ans=max(ans,dp[i][j]+(n-i)*x*(t+j*z)+(n-i)*(t+j*z)*(i-j)*y);//总伤害,并更新ans

注意dp【i】【j】的i从1开始的话,至少选了1个非红塔,因此记得加上 全选红塔的情况

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

const double pi=acos(-1.0);
double eps=0.000001;  

__int64 max(__int64 a,__int64 b)
{return a<b?b:a;}
__int64 dp[1505][1505]; 
int main()
{
	int test;
	cin>>test;
	__int64 i,j;
	int cnt=1;
	__int64 x,y,z,t,n;
	while(test--)
	{
		scanf("%I64d%I64d%I64d%I64d%I64d",&n,&x,&y,&z,&t);
		memset(dp,0,sizeof(dp));
		//dp[i][j]  i+1到n是红,前i个里面放了j个蓝ta,i-j个绿
		__int64 ans=t*x*n;
		for (i=1;i<=n;i++)
		{
			for (j=0;j<=i;j++)
			{
				if (j==0)
					dp[i][j]=dp[i-1][j]+(i-1-j)*y*t;
				else
				{
					__int64 tmp1=dp[i-1][j-1]+(i-j)*y*(t+(j-1)*z);  //j is blue时,在第j造成的伤害
					__int64 tmp2=dp[i-1][j]+(i-1-j)*y*(t+j*z);		//j is green,在第j造成的伤害
					dp[i][j]=max(tmp1,tmp2);
				}
				ans=max(ans,dp[i][j]+(n-i)*x*(t+j*z)+(n-i)*(t+j*z)*(i-j)*y);//总伤害,并更新ans
			}
		}
		
		printf("Case #%d: %I64d\n",cnt++,ans);
	}
	return 0;
	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值