Luogu 6162 [Cnoi2020]四角链

(f(n, k))表示填(n)个格子,填了数字有(k)个的方案数,有初值(f(0, 0) = 1)
不填第(n)个格子的方案数为(f(n - 1, k)),填第(n)个格子时,相当于从(n - (k - 1))个没用过的数中选一个出来填进去,方案数为((n - k + 1) * f(n - 1, k - 1))
发现这个东西和第二类斯特林数的递推式很相似,打个表可以发现(f(n - 1, k) = S(n, n - k)),套上第二类斯特林数的公式,时间复杂度(O(nlogn))
简单证明:

[f(n - 1, k) = f(n - 2, k) + (n - k) * f(n - 2, k - 1) ]

(m = n - k),

[f(n - 1, n - m) = f(n - 2, n - m) + m * f(n - 2, n - m - 1) ]

再令(f(n - 2, n - m - 1) = g(n, m)),

[g(n + 1, m) = g(n, m - 1) + m * g(n, m) ]

(这个地方有一些难懂,事实上(f)的两个参数都加1,(g)中的第二个参数是由(f)中的两个参数作差得到的,所以应当不变)
(g)就是第二类斯特林数。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair <int, int> pin;

const int N = 1e6 + 5;
const int Maxn = 1e6;
const ll P = 998244353LL;

ll fac[N], ifac[N];

template <typename T>
inline void read(T &X) {
    char ch = 0; T op = 1; 
    for (X = 0; ch > '9' || ch < '0'; ch = getchar())
        if (ch == '-') op = -1;
    for (; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X * 10) + ch - '0';
    X *= op;
}

inline ll fpow(ll x, ll y) {
    ll res = 1;
    for (; y > 0; y >>= 1) {
        if (y & 1) res = res * x % P;
        x = x * x % P;
    }
    return res;
}

inline ll getc(ll n, ll m) {
    if (n < m) return 0LL;
    return fac[n] * ifac[m] % P * ifac[n - m] % P;
}

inline void inc(ll &x, ll y) {
    x += y;
    if (x >= P) x -= P;
}

inline void sub(ll &x, ll y) {
    x -= y;
    if (x < 0) x += P;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("sample.in", "r", stdin);
    clock_t st_clock = clock();
#endif

    fac[0] = 1;
    for (int i = 1; i <= Maxn; i++) fac[i] = fac[i - 1] * i % P;
    ifac[Maxn] = fpow(fac[Maxn], P - 2);
    for (int i = Maxn - 1; i >= 0; i--) ifac[i] = ifac[i + 1] * (i + 1) % P;
    
    ll n, m, k, res = 0;
    read(n), read(k);
    m = n - k;
    for (int i = 0; i <= m; i++) {
        if (i & 1) sub(res, getc(m, i) * fpow(m - i, n) % P); 
        else inc(res, getc(m, i) * fpow(m - i, n) % P);
    }
    res = res * ifac[m] % P;
    printf("%lld
", res);

#ifndef ONLINE_JUDGE
    clock_t ed_clock = clock();
    printf("time = %f ms
", (double)(ed_clock - st_clock) / CLOCKS_PER_SEC * 1000);
#endif
    return 0;
}
原文地址:https://www.cnblogs.com/CzxingcHen/p/14477232.html