2018 ACM-ICPC EC-Final I题

题目:https://ac.nowcoder.com/acm/contest/366/I

题意:初始有一个攻击力A=0,,攻击力增量D=0,,给你n个回合,

在每轮回合初,A会自动加上D,每轮回合有三种操作可以选择

1、直接用A+a[i]攻击产生伤害,伤害为A+a[i]

2、增加成长,D+=b[i]

3、增加攻击力,A+=c[i]

要求n轮回合后产生的最大伤害是多少?

思路:

乍一看感觉好复杂,但仔细分析可知第n轮回合肯定是攻击,既然知道最后一次的,那么我们可以往前推

用dp[i][j][k],i表示第i个回合,j表示从i+1到n轮回合中发生了几次攻击,k表示这j次攻击的编号和,

dp[1:100][1:100][1:100*101/2],这样显然空间不够,所以要用滚动数组

时间复杂度100*100*100*101/2

若选1可得dp[i&1][j+1][k+i]=max(dp[i&1][j+1][k+i],dp[(i+1)&1][j][k]+a[i])

若选2可得dp[i&1][j][k]=max(dp[i&1][j][k],dp[(i+1)&1][j][k]+(k-j*i)*b[i]);

其中(k-j*i)*b[i]表示从i+1到n回合中的每次攻击对第i回合选择2多产生的伤害

若选3可得dp[i&1][j][k]=max(dp[i&1][j][k],dp[(i+1)&1][j][k]+j*c[i])

初始状态:dp[n&1][1][n]=a[n]

AC code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=102;
typedef long long ll;
ll dp[2][maxn][maxn*maxn/2];
ll a[maxn],b[maxn],c[maxn];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof dp);
        scanf("%d",&n);
        for(int i=1; i<=n; i++) scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
        dp[n&1][1][n]=a[n];
        for(int i=n-1; i>=1; --i)///n-1开始选,n必选,第n步必攻击
            for(int j=1; j<=n-i; j++)
            {
                int l=(j-1)*(2*i+j)/2+n;
                int r=j*(2*n-j+1)/2;
                for(int k=l; k<=r; k++)
                {
                    dp[i&1][j+1][k+i]=max(dp[i&1][j+1][k+i],dp[(i+1)&1][j][k]+a[i]);///选择攻击造成伤害
                    dp[i&1][j][k]=max(dp[i&1][j][k],dp[(i+1)&1][j][k]+(k-j*i)*b[i]);///选择成长
                    dp[i&1][j][k]=max(dp[i&1][j][k],dp[(i+1)&1][j][k]+j*c[i]);///选择直接增加攻击
                }
            }
        ll ans=0;
        for(int i=1; i<=n; i++)
            for(int k=1; k<=5050; k++)
                ans=max(ans,dp[1][i][k]);
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shaohang_/article/details/86364861