翻看了本题所有的题解, 基本上所有的题解, 都只是贴了个代码 + 状态的定义. 其中较重要的状态的转移都没有啥解释. 这对不太会这题的同学来说, 非常不友好.
建议洛谷官方可以增加一个官方题解, 类似美服or国服的Leetcode, 比如像LeetCode国服官方题解
一个官方的题解的好处是, 至少题解的质量是有保证的(至少不会像本题题解区的题解太差.
本题一句话题解: 考虑从大到小依次填入每个数, 填入的位置只能是边界处. 边界处的判断如下文code
希望有所帮助, peace.
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 6;
int a[N];
std::map<vector<int>, ll> dp;
// 状态: 定义dp[a1][a2][a3][a4][a5]表示第一排的人数为a1, 第二排的人数为a2, ..., 第5排的人数为a5, 的方案数.
// 转移: 考虑到从上到下, 从左往右同学的身高数值都是递增的, 那么最大的值一定在边界处, 所以我们可以考虑按身高数值从大往小的填.
// 如何判断边界, 比如第一排的人数有3个, 第二排的人数也为3个, 那么坐标[1, 3](下标都从1开始)就不可能是边界;
// 相反比如第一排的人数有3个, 第二排的人数只有2个, 那么坐标[1, 3]就是边界.
// 所以只有相邻两排人数, 第一排的人数 > 第二排的人数, 那么第一排的最右边的位置就是边界, 就可以填入.
// 边界: 都填完了即每排人数都为0, 也即a1+a2+a3+a4+a5=0
// 时间复杂度: a1 + a2 + a3 + a4 + a5 == 30, 求a1 * a2 * a3 * a4 * a5的最大值.
// 另外当前5排的人数分别为a1, a2, ..., a5时, 因为我们是从大到小依次填入数的, 所以此时我们要填入的数的值就是a1+a2+a3+a4+a5
ll dfs(int a1, int a2, int a3, int a4, int a5) {
if (a1 + a2 + a3 + a4 + a5 == 0) return 1;
if (dp.count({a1, a2, a3, a4, a5})) return dp[{a1, a2, a3, a4, a5}];
ll ret = 0;
// 填入位置[1, a1]
if (a1 > a2) ret += dfs(a1 - 1, a2, a3, a4, a5);
// 填入位置[1, a2]
if (a2 > a3) ret += dfs(a1, a2 - 1, a3, a4, a5);
// 填入位置[1, a3]
if (a3 > a4) ret += dfs(a1, a2, a3 - 1, a4, a5);
// 填入位置[1, a4]
if (a4 > a5) ret += dfs(a1, a2, a3, a4 - 1, a5);
// 填入位置[1, a5]
if (a5 > 0) ret += dfs(a1, a2, a3, a4, a5 - 1);
return dp[{a1, a2, a3, a4, a5}] = ret;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int k;
cin >> k;
for (int i = 1; i <= k; ++i) cin >> a[i];
cout << dfs(a[1], a[2], a[3], a[4], a[5]);
return 0;
}