[組み合わせ論] [多項式] [ラグランジュ]のカウント

  • ditoly叔父FJ地方チームのトレーニング教材から

ステートメント

  • そこ\(M \)正の整数変数、どのように多くの値のプログラムを見つけます

  • このようなことすべての変数以上、\(S \)

  • そして、フロント\(N- \)変数の値を超えない(\ T)を\

  • 回答(9 + 10 ^ 7 \)\モジュロ

  • \(MN \ le1000 \)、\ (M \ 10 ^ 9 \)、\ (T \ 10 ^ 5 \)、\ (S \ S \ 10 ^ {18} \)

溶液

  • ための\(NT \ Sル\ル18が10 ^ {} \) 我々の溶液は以下のように表現することができるように。

  • \ [\ sum_ {X_1 = 1} ^ T \ sum_ {X_2 = 1} ^ T \ドット\ sum_ {x_nに関する= 1} ^ T \ binom {S- \ sum_ {I = 1} ^ nx_i} {MN} \ ]

  • \(S = S-(MN)+ 1- \ sum_ ^ nx_i \ {iが= 1})

  • 上記式どの程度であるの組み合わせの数注目\(S \)多項式を、特に、それはに等しい(\ \ FRAC {S ^ { \上線{MN}}} {(MN)!} \)

  • 前記\(N ^ {\上線M } \) を表し(N- \)\ \(M \)倍、即ち、電力の増加prod_ {I = 0 \(\ } ^ {M-1}(N + I)\

  • 多項式、数スターリング最初のタイプを生成するために機能することにより得ることができる\(I \)次の項の係数\(\ FRAC {\ {始める bmatrix} MN \\ I \端を{bmatrix}} {(MN) !} \) \(\開始{bmatrix} N \\ M \端{bmatrixは} \) 第一のタイプのスターリング数であり、すなわち\(N- \)要素に(M \)\ラウンドプログラム番号が並びます

  • 多項式形式の数として表される組成の後、我々は最初に考えると決定\(N- \)全ての変数\(T ^ N \)値の種類に対応する\(S ^ I \)(\ ( 0 \ルI \ルマンガン\) 合計が、問題は良い解決策になることができます

  • :DP検討\(F [I] [J]が\)を表し(X_ {1つの\ドットI \ \}) とすべての値\((S - M + N + 1- \ sum_ {k = 1} ^ ix_k )^ J \)

  • 方法の観点から\(F [i]が\)に移した(F [I + 1] \ \)

  • 即ち転送列挙\(X_ {I + 1} \) の値、セット\(S = S-M + N + 1- \ sum_ {k = 1} ^ ix_k \)

  • それは見つけることができます:

  • \ [\ sum_ {k = 1} ^ T(SK)^ J = \ sum_ {k = 0} ^ J(-1)^ {JK} \ binom JKS ^ ksum(JK、T)\]

  • 前記\(SUM(P、N - )= \ sum_ = {I}。1 ^のNi ^ P \) 補間を利用することができる\(O(P)\)が決定されます

  • DP転送を持って、私たちはそう:

  • \ [F [I + 1]〜[J] = \ sum_ {k = 0} ^ J(-1)^ {JK} \ binom jksum(JK、T)F [i]が[K] \]

  • 離れ組み合わせの数:

  • \ [\ FRAC {F [I + 1] [J]} {J!} = \ sum_ {k = 0} ^ J \ FRAC {( - 1)^ {JK}和(JK、T)} {(JK )!} \ FRAC {F [i]が[K]} {K!} \]

  • 多項式提供\(F_iと(X)= \ sum_ {J = 0} ^ {Mnは} F [I] [J] X ^ J \)、\ (G(X)= \ sum_ ^ {Mnは{I = 0} } \ FRAC {!( - 1 )^ ISUM(I、T)} {I} X ^ I \)

  • そして、それが取得するのは簡単です\(F_n(X)= G(X)のn ^ \)迅速な乗算の電源、

  • 複雑\(O((MN)^ 2 \ログN)\) または\(O((MN)^ 2)\)

コード

#include <bits/stdc++.h>

const int N = 1010, rqy = 1e9 + 7;

typedef long long ll;

ll s;
int t, n, m, l, pw[N][N], f[N], fac[N], inv[N], invt[N], g[N], ans, S[N][N];

int qpow(int a, int b)
{
    int res = 1;
    while (b)
    {
        if (b & 1) res = 1ll * res * a % rqy;
        a = 1ll * a * a % rqy;
        b >>= 1;
    }
    return res;
}

int calc(int T)
{
    int sum = 0, res = 0, al = 1;
    for (int i = 1; i <= T + 2; i++) al = 1ll * al * (t - i + rqy) % rqy;
    for (int i = 1; i <= T + 2; i++)
    {
        sum = (sum + pw[i][T]) % rqy;
        if (i == t) return sum;
        int delta = 1ll * al * invt[i] % rqy *
            inv[i - 1] % rqy * inv[T + 2 - i] % rqy;
        if (T + 2 - i & 1) delta = (rqy - delta) % rqy;
        res = (1ll * delta * sum + res) % rqy;
    }
    return res;
}

int main()
{
    std::cin >> s >> t >> n >> m;
    l = m - n; s -= l - 1;
    f[0] = fac[0] = inv[0] = inv[1] = 1;
    for (int i = 1; i <= l + 2; i++) fac[i] = 1ll * fac[i - 1] * i % rqy;
    for (int i = 2; i <= l + 2; i++)
        inv[i] = 1ll * (rqy - rqy / i) * inv[rqy % i] % rqy;
    for (int i = 2; i <= l + 2; i++) inv[i] = 1ll * inv[i] * inv[i - 1] % rqy;
    for (int i = 1; i <= l + 2; i++)
    {
        pw[i][0] = 1;
        for (int j = 1; j <= l; j++) pw[i][j] = 1ll * pw[i][j - 1] * i % rqy;
    }
    for (int i = 1; i <= l + 2; i++) invt[i] = qpow((t - i + rqy) % rqy, rqy - 2);
    for (int i = 1; i <= l; i++) f[i] = s % rqy * f[i - 1] % rqy;
    for (int i = 0; i <= l; i++) f[i] = 1ll * f[i] * inv[i] % rqy;
    for (int i = 0; i <= l; i++)
    {
        g[i] = 1ll * calc(i) * inv[i] % rqy;
        if (i & 1) g[i] = (rqy - g[i]) % rqy;
    }
    while (n)
    {
        if (n & 1) for (int i = l; i >= 0; i--)
        {
            f[i] = 1ll * f[i] * g[0] % rqy;
            for (int j = 1; j <= i; j++)
                f[i] = (1ll * f[i - j] * g[j] + f[i]) % rqy;
        }
        for (int i = l; i >= 0; i--)
        {
            g[i] = 1ll * g[i] * g[0] % rqy;
            if (i) g[i] = (g[i] + g[i]) % rqy;
            for (int j = 1; j < i; j++)
                g[i] = (1ll * g[i - j] * g[j] + g[i]) % rqy;
        }
        n >>= 1;
    }
    S[0][0] = 1;
    for (int i = 1; i <= l; i++)
        for (int j = 1; j <= i; j++)
            S[i][j] = (1ll * S[i - 1][j] * (i - 1) + S[i - 1][j - 1]) % rqy;
    for (int i = 0; i <= l; i++)
        ans = (1ll * f[i] * fac[i] % rqy * S[l][i] + ans) % rqy;
    return std::cout << 1ll * ans * inv[l] % rqy << std::endl, 0;
}

おすすめ

転載: www.cnblogs.com/xyz32768/p/11953280.html