#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>

using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(n + 1, 0);
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    long long maxGrade = 0;
  	// (击败怪物数%10 + 1)作为a[i]系数影响杀怪的最终奖励,系数 j 取值范围只有 0 ~ 9 
    // dp[i][j] 遇到第i个怪物时,在系数j下可以获得的最大奖励
    vector<vector<long long>> dp(n + 1, vector<long long>(10, 0));
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j <= 9 && j <= i; ++j) {

            dp[i][j] =  max(dp[i - 1][j] + i, dp[i][j]); // 不杀怪

            int prev = (j == 0) ?  9 : j - 1;

            long long temp = ( i <= 9 && j == 0) ? 0 : dp[i - 1][prev] + a[i] * (j + 1);
            dp[i][j] = max(temp, dp[i][j]); // 杀怪,当i不超过9的时候,不可能出现 j = 0(最少杀十个冤大头才会出现 j = 0 的情况 ),不能增加奖励

            maxGrade = max(maxGrade, dp[i][j]);
        }
    }
    cout << maxGrade << endl;
}

一、解题思路

1、不杀怪奖励 i, 杀怪奖励 a[i]*( count mod 10 + 1)

2、为什么每一步都贪心,取奖励最大值不行?

考虑极端情况:

数组a长度为11(包含十个小怪物) ,a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10000] (0想象成哨兵,为了使索引和击杀怪物数量对应,无实际用途),这种情况下前9次按照贪心思路,显然应该给它们全杀喽!!!那么杀死第十个倒霉蛋的时候 10 mod 10 = 0,杀怪奖励为 a[i] = 10000, 如果前面积攒一个功德,让生命值为10000的倒霉蛋第九个死,杀怪奖励显然为 10 * a[i] , 奖励翻十倍!!!

3、dp设计思路,及递推公式

(1)状态:第i个小怪兽,j杀怪奖励的系数(mod完后取0 ~ 9,可以想象成攒大招)

dp[i][j] 遇到第i个怪物时,在系数j下可以获得的最大奖励(如果杀)

(2)递推公式:

不杀怪时:max(dp[i - 1][j] + i, dp[i][j]) 参照遇见前 i - 1 个怪物在系数j下的最大奖励

杀怪时:max(dp[i - 1][prev] + a[i] * (j + 1) , dp[i][j]) 参照遇见前 i - 1 个怪物在前一个系数为(prev = j - 1 或 9)下的最大奖励

注意当i <= 9的时候不可能出现“已经杀死十个倒霉蛋”的状况,所以此时的杀怪奖励应该为0(之前没处理这里,和系统一顿抢分,导致每次输出值都比测试用例的大,哈哈~~~)。

初始化dp数组的大小为( n + 1, 10),第一行初始化为0,理解为没遇见怪物前,不管有多少大招都没有奖励值。