NKOI 2422 植物大战僵尸[6月月赛题c]

Problem

植物大战僵尸(mtower.cpp/c/pas)

题目描述

何老板喜欢玩植物大战僵尸,在游戏里有一条水平道路,道路的一端是入口,另一端是房子。僵尸会从道路的入口一端向房子一端移动。这条道路刚好穿过N块连续的空地。初始时,僵尸通过每块空地的时间是T秒。玩家可以在这N个空地中种植植物以攻击经过的僵尸,每块空地中只能种植一种植物。

共有三种不同类型的植物,分别是红草、蓝草和绿草,作用分别是攻击、减速以及下毒。每种植物只能在僵尸通过它所在空地的这段时间内攻击到僵尸。

当僵尸经过一块红草所在的空地时,每秒钟生命值会减少R点;当僵尸从一块蓝草所在的空地走出之后,通过每块空地的时间延长B秒;当僵尸从一块绿草所在的空地走出之后,每秒钟会因中毒减少G点生命值。蓝草的减速效果和绿草的下毒效果是可以累加的。也就是说,僵尸通过n块蓝草所在的空地之后,它通过每块空地的时间会变成T+B*n秒;僵尸通过n块绿草所在的空地之后,它每秒钟会因中毒失去G*n点生命值。注:减速和中毒效果会一直持续下去

何老板想知道:怎样在这N块空地里种植各种类型的植物,才能使通过的僵尸失去的生命值最大。输出这个最大值。

输入格式

一行,五个空格隔开的整数N、R、G、B、T。

输出格式

一行,一个整数,即通过的僵尸失去的最大的生命值。

输入样例

5 4 3 2 1

输出样例

82

数据范围

20%的数据满足N<=12。

50%的数据满足N<=100。

100%的数据满足1<=N<=2000; 0 <= R, G, B <= 65536; 0 <= T <= 3。


这道题的难点主要在于想到这是一个动规题

经过分析,我们知道这是动规之后,就开始思考状态转移方程了

首先我们应该明白,红草放在最后的时候,我们得到的解才可能是最优的,因为红草的攻击是暂时性的,而蓝草和绿草的攻击都是持续性的

我们设最后k个位置放的是红草,那么前left=n-k个位置就是剩下的绿草和蓝草放的位置

我们用f[i][j]来表示前i+j个位置中绿草放i个,蓝草放j个的最大伤害

而求解f[i][j]实际上是在对第i+j个格子进行讨论

那么对于f[i][j]来说只有两种决策,要么放绿草,要么放蓝草

因此方程如下

 f[i][j]=max {f[i1][j]+(T+i*B)*(j-1)*G;   表示最后一个位置放绿草,通过最后一格的时间是T+bb*B,中毒造成的伤害是每时间(gg-1)*G
                  f[i][j-1]+(T+(i-1)*B)*j*G; } 表示最后一个位置放蓝草,通过最后一格的时间是T+(bb-1)*B,中毒造成的伤害是每时gg*G

对于每个f[i][j],加上最后的k个红草带来的伤害,以及在红草的区域由于中毒带来的伤害(后者易忽视),找到最优值即可
  ans= max{f[i][j]+k*(T+i*B)*(R+j*G)} 

由于题目中限制了空间只有3m,因此要用滚动数组优化

#include<iostream>
#define LL long long
using namespace std;
const LL inf=2e9;
LL N,G,B,T,R;
LL f[3][3];
int main(){
	cin>>N>>R>>G>>B>>T;
	LL i,j,k,ans=0;
	for(k=N;k>=1;k--){//注意,根据状态转移方程特征,这里的K应该逆序枚举
		LL left=N-k;
		for(i=0;i<=left;i++){
			LL j=left-i;
			if(i>0)
			    f[i&1][j&1]=max(f[i&1][j&1],f[(i-1)&1][j&1]+(T+j*B)*G*(i-1));
			if(j>0)
			    f[i&1][j&1]=max(f[i&1][j&1],f[i&1][(j-1)&1]+(T+(j-1)*B)*G*i);
			ans=max(ans,f[i&1][j&1]+k*(T+j*B)*(R+i*G));
		}
	}
	cout<<ans;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值