1. 程式人生 > >POJ 2279【楊氏矩陣+鉤長公式】

POJ 2279【楊氏矩陣+鉤長公式】

題目連結: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;
}