http://acm.hdu.edu.cn/showproblem.php?pid=4939
题意:塔防游戏:在长度为n的路上放置n座炮塔。有一只怪兽,经过单位长度需要时间t。现在有三种炮塔,
红塔:只对经过该点的怪兽造成每秒x点的伤害,
绿塔:怪兽经过这座塔之后的每一秒,每秒造成y点伤害(伤害是累加的,比如怪兽已经经过两座绿塔,那么伤害就是每秒2*y点),
蓝塔:使怪兽经过单位长度的时间增加z秒(时间也是累加的)。
现在要求你来建塔,使怪兽受到的伤害最大,求这个最大伤害。
题解:可以发现,红塔一定是建造在所有塔之后的,即最后面。因为红塔是及时伤害,会受蓝塔的效果影响,而且会减少绿塔的伤害。
那么可以想先是全部建造红塔。然后从第一个开始,每个换成蓝塔或者绿塔,每次更新答案。
dp[i][j]:前i座塔建造j座蓝塔的最大伤害。
转移方程:
a=dp[i-1][j]+(i-j-1)*y*(t+j*z),第i座不建蓝塔,建绿塔。
b=dp[i-1][j-1]+(i-j)*y*(t+(j-1)*z),第i座建蓝塔,不建绿塔。
dp[i][j]=max(a,b)
最后更新答案时,加上n-i段的红塔的伤害即可。
代码:
#include<bits/stdc++.h>
#define debug cout<<"aaa"<<endl
#define d(a) cout<<a<<endl
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define MIN_INT (-2147483647-1)
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807i64
#define MIN_LL (-9223372036854775807i64-1)
using namespace std;
const int N = 1500 + 5;
const int mod = 1000000000 + 7;
const double eps = 1e-8;
LL dp[N][N];//dp[i][j]:前i个有j个蓝塔的最大伤害
int main(){
int tt,cas=0,n;
LL x,y,z,t,ans,a,b;
scanf("%d",&tt);
while(tt--){
scanf("%d%lld%lld%lld%lld",&n,&x,&y,&z,&t);
ans=n*x*t,mem(dp,0);
for(int i=1;i<=n;i++){
for(int j=0;j<=i;j++){//前i个中有j座蓝塔
if(j==0){
dp[i][j]=dp[i-1][j]+(i-j-1)*y*t;//不放蓝塔
}
else{
a=dp[i-1][j-1]+(i-j)*y*(t+(j-1)*z);//放蓝塔
b=dp[i-1][j]+(i-j-1)*y*(t+j*z);//不放蓝塔
dp[i][j]=max(a,b);
}
//n-i段的伤害
a=dp[i][j]+(n-i)*x*(t+j*z)+(n-i)*(i-j)*y*(t+j*z);
ans=max(a,ans);
}
}
printf("Case #%d: %lld\n",++cas,ans);
}
return 0;
}