POJ 2279【楊氏矩陣+鉤長公式】
阿新 • • 發佈:2019-01-01
題目連結: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; }