题目链接:http://poj.org/problem?id=22793
题意:给出n行,每行有人数限制a[i],并且a[i]>=a[i+1],总人数暂且称为tot=∑a[i],把 1~tot 这些数字填入矩阵,使得矩阵满足每行单调递增,每列单调递增,求满足要求的矩阵数目。
杨氏矩阵又叫杨氏图表,它是这样一个矩阵,满足条件:
(1)如果格子(i,j)没有元素,则它右边和上边的相邻格子也一定没有元素。
(2)如果格子(i,j)有元素a[i][j],则它右边和上边的相邻格子要么没有元素,要么有元素且比a[i][j]大。
1 ~ n所组成杨氏矩阵的个数可以通过下面的递推式得到:
如图就是n=3时的杨氏矩阵。
钩子公式:对于给定形状,不同的杨氏矩阵的个数为:n!除以每个格子的钩子长度加1的积。其中钩子长度定义为该格子右边的格子数和它上边(题目中是下边)的格子数之和。
题解:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int m, a[33];
int sum[1005];
ll gcd(ll a, ll b){
return b ? gcd(b, a%b) : a;
}
int main()
{
scanf("%d", &m);
int id = 0;
for(int i = 1; i <= m; i++){
scanf("%d", &a[i]);
}
for(int i = 1; i <= m; i++){//第i行
for(int j = 1; j <= a[i]; j++){//第j列
id++;
for(int k = i+1; k <= m; k++){//第i行下面的行
if(a[k] >= j) sum[id]++;//说明第id个元素下面有元素
else break;
}
sum[id] += (a[i] - j + 1);//加上右边的元素个数在加1
}
}
ll a = 1, b = 1, tmp = 1;
ll ans = 0;
for(int i = 1; i <= id; i++){
a *= i;
b *= sum[i];
tmp = gcd(a, b);
if(tmp != 1){
a /= tmp;
b /= tmp;
}
}
ans = a/b;
printf("%lld\n", ans);
return 0;
}