一个建议
查看原帖
一个建议
36078
uhgariej楼主2023/2/6 01:02
  • 翻看了本题所有的题解, 基本上所有的题解, 都只是贴了个代码 + 状态的定义. 其中较重要的状态的转移都没有啥解释. 这对不太会这题的同学来说, 非常不友好.

  • 建议洛谷官方可以增加一个官方题解, 类似美服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;
}
2023/2/6 01:02
加载中...