hdu 4372 Count the Buildings 第一类斯特林数

第一类斯特林数

对于n个数,分成k组,每组是一个环排列(非空)
S ( n , k ) = ( n 1 ) S ( n 1 , r ) + S ( n 1 , r 1 ) S(n,k)=(n-1)*S(n-1,r)+S(n-1,r-1)

分析

一共n个楼,高度分别为1~n,现在从左边往右边看是f个楼,从右边往左边看是b个楼
我们发现最高楼两边都可以看见,故忽略不计
从最高楼到两边,可见楼是一个递减的序列,这个一共可以分成(f+b-2)组,对于每组,我们要保证最值的位置确定(最左或最右),故这是个环排列,这个贡献为 S ( n 1 , f + b 2 ) S(n-1,f+b-2)
然后我们要从 ( f + b 2 ) (f+b-2) 组里选 ( f 1 ) (f-1) 组或者 ( b 1 ) (b-1) 组,故:
a n s = C f + b 2 f 1 S ( n 1 , f + b 2 ) ans=C_{f+b-2}^{f-1}*S(n-1,f+b-2)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template <typename T>
void out(T x) { cout << x << endl; }
ll fast_pow(ll a, ll b, ll p) {ll c = 1; while(b) { if(b & 1) c = c * a % p; a = a * a % p; b >>= 1;} return c;}
ll exgcd(ll a, ll b, ll &x, ll &y) { if(!b) {x = 1; y = 0; return a; } ll gcd = exgcd(b, a % b, y, x); y-= a / b * x; return gcd; }
const int N = 2e3 + 10;
const int mod = 1e9 + 7;
ll C[N][N], S[N][N];
void init()
{
    for(int i = 0; i < N; i ++)
    {
        C[i][0] = 1;
        S[i][i] = 1;
    }
    for(int i = 1; i < N; i ++)
        for(int j = 1; j < N; j ++)
        {
            if(i >= j)
                C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
            S[i][j] = ((i - 1) * S[i - 1][j] % mod + S[i - 1][j - 1]) % mod;
        }
}
int main()
{
    ios::sync_with_stdio(false);
    init();
    int t;
    cin >> t;
    while(t --)
    {
        int n, f, b;
        cin >> n >> f >> b;
        if(f + b - 1 > n)
        {
            cout << 0 << endl;
            continue;
        }
        cout << (C[f + b - 2][f - 1] * S[n - 1][f + b - 2]) % mod << endl;
    }
}
发布了76 篇原创文章 · 获赞 5 · 访问量 1310

猜你喜欢

转载自blog.csdn.net/qq_43101466/article/details/102762169