ACwing 271 Mr.Yang's Picture Permutations
题面
有 N 个学生合影,站成左端对齐的 k 排,每排分别有 N1,N2,…,Nk 个人。 (N1≥N2≥…≥Nk)
在合影时要求每一排从左到右身高递增,每一列从后到前身高也递增。
第 i 个人的身高为 i
\(1 \le k \le 5,N \le 30\)
题解
这道题我们可以按照从 1 到 n 的顺序考虑每个人的位置,设每排的人数分别为 \(a_1,a_2,a_3...a_k\)
第 i 个人可以放在第 i 排,当且仅当 \(a_i < N_i\) 并且 \(a_{i - 1} > a_i\)
我们设 \(f[a_1][a_2][a_3][a_4][a_5]\) 表示每排已经放的人数为 \(a_1...\) 的方案数
初始为 \(f(0,0,0,0,0) = 1\) ,目标状态为 \(f(N_1, N_2...)\) ,\(k\) 不足 5 的我们可以补齐,令 \(N_i\) 为 0 即可
转移(假设放在第 \(1\) 排):\(f(a_1 + 1, a_2...) += f(a_1,a_2...)\)
由均值不等式,最坏情况下有 \((\frac N k ) ^ k\) 个状态,计算每个状态的计算量为 \(O(k)\) 所以总的时间复杂度为 \(O(k(\frac N k)^k)\)
code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>using namespace std;typedef long long ll;const int N = 35;ll f[N][N][N][N][N];int main () {int n;while (cin >> n && n) {int s[5] = {};for (int i = 0; i < n; i++) cin >> s[i];memset (f, 0, sizeof f);f[0][0][0][0][0] = 1;for (int a = 0; a <= s[0]; a ++) {for (int b = 0; b <= s[1]; b ++) {for (int c = 0; c <= s[2]; c ++) {for (int d = 0; d <= s[3]; d ++) {for (int e = 0; e <= s[4]; e ++) {auto now = f[a][b][c][d][e];f[a + 1][b][c][d][e] += now;if (b < a) f[a][b + 1][c][d][e] += now;if (c < b) f[a][b][c + 1][d][e] += now;if (d < c) f[a][b][c][d + 1][e] += now;if (e < d) f[a][b][c][d][e + 1] += now;}}}}}cout << f[s[0]][s[1]][s[2]][s[3]][s[4]] << endl;}return 0;
}