POJ 2279 Mr. Young's Picture Permutations
题目链接:POJ 2279 Mr. Young's Picture Permutations
题目大意:
\(n\)个学生站成\(k\)排,每排分别有\(N1,N2,N3……Nk\)名学生。要求每排的学生的身高单调递增,而每一排的同位的同学的身高单调递减。求总的方案数。
题解:
注意到\(k\)很小,我们就可以暴力状态了,而要表现单调递增,故维护一个从左至右边矮的阶梯。
以有\(5\)列为例,设\(f[a][b][c][d][e]\)表示第\(1\)列已经填的数字高度为\(a\),第\(2\)列高度为\(b\),...,第\(5\)列的高度为\(e\)的,现在填到数字\(a+b+c+d+e\)方案数,并保证转移时\(a \geq b \geq c \geq d \geq e\),于是当一个新的数字填的时候一定比所有的数字都要大。
递推式为:
\[f[a+1][b][c][d][e]+=f[a][b][c][d][e]
\]
\[f[a][b+1][c][d][e]+=f[a][b][c][d][e]
\]
\[f[a][b][c+1][d][e]+=f[a][b][c][d][e]
\]
\[f[a][b][c][d+1][e]+=f[a][b][c][d][e]
\]
\[f[a][b][c][d][e+1]+=f[a][b][c][d][e]
\]
边界:\(f[0][0][0][0][0]=1\),其余为\(0\)。
答案:\(f[n1][n2][n3][n4][n5]\)。
#include <cstdio>
#include <cstring>
using namespace std;
int row, n[6];
int main() {
while (scanf("%d", &row) && row) {
memset(n, 0, sizeof(n));
for (int i = 1; i <= row; ++i) {
scanf("%d", &n[i]);
}
unsigned int f[n[1] + 1][n[2] + 1][n[3] + 1][n[4] + 1][n[5] + 1];
memset(f, 0, sizeof(f));
f[0][0][0][0][0] = 1;
for (int i1 = 0; i1 <= n[1]; ++i1) {
for (int i2 = 0; i2 <= n[2]; ++i2) {
for (int i3 = 0; i3 <= n[3]; ++i3) {
for (int i4 = 0; i4 <= n[4]; ++i4) {
for (int i5 = 0; i5 <= n[5]; ++i5) {
unsigned int t = f[i1][i2][i3][i4][i5];
if (i1 < n[1]) {
f[i1 + 1][i2][i3][i4][i5] += t;
}
if (i2 < n[2] && i1 > i2) {
f[i1][i2 + 1][i3][i4][i5] += t;
}
if (i3 < n[3] && i2 > i3) {
f[i1][i2][i3 + 1][i4][i5] += t;
}
if (i4 < n[4] && i3 > i4) {
f[i1][i2][i3][i4 + 1][i5] += t;
}
if (i5 < n[5] && i4 > i5) {
f[i1][i2][i3][i4][i5 + 1] += t;
}
}
}
}
}
}
printf("%u\n", f[n[1]][n[2]][n[3]][n[4]][n[5]]);
}
return 0;
}