I题
题意:一共有n轮,你每次可以选择三种操作,第一种就是攻击怪兽,造成伤害A+ai,第二种就是提高自己的属性,以后每轮攻击力都增加bi,第三种提高攻击力,攻击力增加ci,问你最多能造成的伤害是多少。
题解:这题我一看n,想暴力,发现不行,因为你不能确定那几轮操作干嘛,所以只能dp,dp也不是那么容易,首先这题要倒序dp,倒序dp有什么好处呢,就是如果一个题不要考虑前效应就能用,设dp[i][j][k],代表第i轮到第n轮,攻击了j次,攻击j次的轮数下标之和(为啥要d这个呢,因为我对于第二种操作我不是那么容易算贡献,那么第二种操作的贡献,如果我攻击几次的轮数都知道,那么对于该次操作它的贡献为 b[i]*(x1-i+x2-i+…xj-i),那么你会发现我们并不用求具体攻击在那几轮,只需要知道j次攻击下标之和就能算出第二次操作的贡献)。
那么dp怎么转移呢?
dp[i+1][j][k+j] = max(dp[i][j][k] + max(j * c[i], b[i] * (k+j)),dp[i+1][j][k+j]);
//这是执行二三操作
dp[i+1][j+1][j+k] = max(dp[i+1][j+1][j+k],dp[i][j][k]+a[i]);
//这是执行操作一
然后为什么要到下轮就是k+j了,因为我们是倒着dp的,所以相当于起点往后移了,那么j次攻击的下标是不是都+1了,那么j次就+j。
(这题我学了巨久,代码借鉴橘子猫学长的)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[110],b[110],c[110];
ll dp[2][110][5060];
void clear(int cul)
{
for(int i=0;i<110;i++) for(int j=0;j<5060;j++) dp[cul][i][j] = -1;
}
int main()
{
int t;scanf("%d",&t);
while(t--)
{
ll ans = 0 ;
int cul = 0;
int n;scanf("%d",&n);
for(int i=n;i>=1;i--) scanf("%d%d%d",&a[i],&b[i],&c[i]);
clear(cul);dp[0][0][0] = 0;
for(int i=1;i<=n;i++)
{
cul = !cul;
clear(cul);
for(int j=0;j<i;j++)
for(int k=0;k<=i*(i-1)/2;k++)
{
if(dp[!cul][j][k]==-1) continue;
dp[cul][j+1][k+j] = max(dp[cul][j+1][k+j],dp[!cul][j][k]+a[i]);
ans = max(dp[cul][j+1][k+j],ans);
dp[cul][j][k+j] = max(dp[!cul][j][k]+max(1LL*j*c[i],1LL*b[i]*(k+j)),dp[cul][j][k+j]);
ans = max(dp[cul][j][k+j],ans);
}
}
printf("%lld\n",ans);
}
}