1 ACwing 271 Mr

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;
}
posted @ 2025-10-05 17:59  michaele  阅读(7)  评论(0)    收藏  举报