1. 程式人生 > 實用技巧 >HDU - 4372 Count the Buildings 組合數學 第一類斯特林數

HDU - 4372 Count the Buildings 組合數學 第一類斯特林數

第一類斯特林數

\[斯特林輪換式 S[n][k]表示將n個兩兩不同的元素,劃分為k個非空圓排列的方案數 \]

遞推式:

\[S[n][k] = S[n-1][k-1]+(n - 1)\cdot S[n-1][k] \]

邊界:

\[S[n][0]=[n=0] \]

HDU 4372

題意:

有n座高分別為\(1\sim n\)的城市在一條水平線上,從左能看到\(F\)座城市,從右能看到B座城市,問有幾種城市的排列方案。

題解:
首先最高的那座樓無論從左還是從右都會看到,因此最高的那座位置都是固定的。

從左看的\(F - 1\)座必然是高度遞增的,因此我們可以把這\(F-1\)座樓分組,每組的最左端也就是每組的最高的那座樓。組內剩下的$ k - 1$ 座進行全排列有\((k - 1)!\)

種情況,相當於\(k\)個元素進行圓排列。對於每一組進行圓排列,又由於前\(F-1\)是升序,因此相當於再從\(F-1+B-1\)中選擇\(F-1\)個。

因此

\[ans = \tbinom{F-1+B-1}{F-1} \cdot S[n-1][F-1+B-1] \]

ll C[2005][2005];
ll S[2005][2005];


void get_C()
{
    C[0][0] = 1;
    for (int i = 1; i <= 2000; i++)
    {
        C[i][0] = 1;
        for (int j = 1; j <= i; j++)
            C[i][j] = C[i - 1][j] + C[i - 1][j - 1], C[i][j] %= MOD;
    }
}

void get_S() {
    S[0][0] = 1;
    for (int i = 1; i <= 2000; i++) {
        for (int j = 1; j <= i; j++)
            S[i][j] = S[i - 1][j - 1] + (i - 1) * S[i - 1][j] % MOD, S[i][j] %= MOD;
    }
}

int main() {
    get_C();
    get_S();
    int T = readint();
    while (T--) {
        ll n = readll();
        ll f = readll();
        ll b = readll();
        if (f - 1 + b - 1 > n) {
            puts("0");
            continue;
        }
        ll res = C[f - 1 + b - 1][f - 1] * S[n - 1][f - 1 + b - 1];
        res %= MOD;
        Put(res);
        puts("");
    }
}